<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2025-04-28T18:18:38+03:00</updated><id>/feed.xml</id><title type="html">Orestis Papadopoulos</title><subtitle>I&apos;m Orestis Papadopoulos. I work as a software developer. This is my blog, I write about software, sounds and Swift.
</subtitle><author><name>Orestis Papadopoulos</name></author><entry><title type="html">How I Track My Blog’s Analytics with Val Town</title><link href="/valtown/http/analytics/blog/jekyll/2025/04/15/blog-analytics.html" rel="alternate" type="text/html" title="How I Track My Blog’s Analytics with Val Town" /><published>2025-04-15T09:33:36+03:00</published><updated>2025-04-15T09:33:36+03:00</updated><id>/valtown/http/analytics/blog/jekyll/2025/04/15/blog-analytics</id><content type="html" xml:base="/valtown/http/analytics/blog/jekyll/2025/04/15/blog-analytics.html"><![CDATA[<p>Random morning thoughts: how many people actually visit this blog? Where do they come from? What if I could just spend a little time to build my own <strong>analytics</strong>?</p>
<p>I used <a href="https://plausible.io">Plausible</a> Analytics for a while, it's a great Firebase alternative and worth checking out. It has a smooth interface and is easy to set up. However, I realized I don’t need all the features it offers, and the traffic I get is (probably — last time I checked) not huge. So my needs for <strong>analytics</strong> are really simple:</p>
<p>I want to know:</p>
<ul>
<li>How many people visit my blog (in the last week, month, year)</li>
<li>Where they come from (which social media, search engine, etc.)</li>
<li>Which posts are the most visited</li>
</ul>
<p>It shouldn't be that hard, right?</p>
<h2 id="server-setup">Server Setup</h2>
<p>I decided to use <a href="https://www.val.town/dashboard">Val Town’s</a> free tier to set up an HTTP server backed by a simple SQLite database. <strong>Val Town</strong> is a website where you can write serverless JavaScript functions, with an emphasis on collaboration.</p>
<p>The server basically has two endpoints:</p>
<ul>
<li>A <strong>POST</strong> endpoint that registers <strong>events</strong> by writing to a <strong>SQLite</strong> database.</li>
<li>A <strong>GET</strong> endpoint that returns all the <strong>events</strong> found in the database.</li>
</ul>
<p>It also serves a <a href="https://orjpap-bloganalyticsserver.web.val.run/analytics.js">JS script</a>. This script gets injected into the <strong>&lt;head&gt;</strong> of every page of my blog (you just got injected too) and sends events to the <strong>POST</strong> endpoint.</p>
<p>In order to protect the server from unauthorized <strong>reads</strong>, different keys (and header) for the GET endpoint. Finally, serving the script directly from the server allows for easier API key updates for the POST endpoint. Ideally in the future, I would like to create a mechanism for automatically expiring/rotating the keys (any tips would be appreciated).</p>
<h2 id="events">Events</h2>
<p>An event looks like this:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://orjpap.github.io/"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"referrer"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://www.google.com/"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"timestamp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-04-15T10:19:48.580Z"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"user_agent"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Safari/605.1.15"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>You can store up to <strong>10MB</strong> in SQLite on the free plan. GPT estimates each row to be around <em>290–300 bytes</em>, which means I can probably store about <strong>35k events</strong>. In the very pleasant event of reaching the max limit, I can download my data as JSON, store it somewhere, and then delete and continue tracking or upgrade to a paid tier.</p>
<h2 id="viewing-the-data">Viewing the Data</h2>
<p>I can directly manage the sqlite database using a very handy val called <a href="https://www.val.town/v/nbbaier/sqlite_explorer">sqlite_explorer</a>. It allows me to run SQL queries and offers a basic UI that gets the job done.</p>
<p><img src="/assets/images/2025-04-15-blog-analytics.assets/sqlite-explorer.png" alt="sqlite-explorer" /></p>
<p>I also made a Swift <a href="https://github.com/orjpap/orjpap.github.io/blob/8bbc591d0df3430e839d1c8e801532179b9ec40d/scripts/analytics.swift">script</a> to read my analytics through the terminal. It's quite primitive, but it's all I need to check every once in a while.</p>
<p><img src="/assets/images/2025-04-15-blog-analytics.assets/analytics-swift-terminal.png" alt="1" /></p>
<h2 id="sharing">Sharing</h2>
<p>That’s pretty much it! I’m really impressed that I pulled this together in less than a day. I’m glad it’s already running and even more glad I’ve already managed to collect some data from real users.</p>
<p>Feel free to fork my Val Town server if you're interested in rolling your own analytics.</p>
<iframe width="100%" height="400px" src="https://www.val.town/embed/orjpap/simpleAnalytics" title="Val Town" frameborder="0" allow="web-share" allowfullscreen></iframe>
<p>Special thanks to <a href="https://github.com/mrfratello">John Syomochkin</a> for his tips about securing the GET endpoint.</p>]]></content><author><name>Orestis Papadopoulos</name></author><category term="Valtown" /><category term="HTTP" /><category term="Analytics" /><category term="Blog" /><category term="Jekyll" /><summary type="html"><![CDATA[Random morning thoughts: how many people actually visit this blog? Where do they come from? What if I could just spend a little time to build my own analytics?]]></summary></entry><entry><title type="html">AVAudioEffectNode: Configurable Input-Output</title><link href="/swift/low-level/audio/avfoundation/2024/12/01/avaudioeffectnode-input-output.html" rel="alternate" type="text/html" title="AVAudioEffectNode: Configurable Input-Output" /><published>2024-12-01T08:33:36+02:00</published><updated>2024-12-01T08:33:36+02:00</updated><id>/swift/low-level/audio/avfoundation/2024/12/01/avaudioeffectnode-input-output</id><content type="html" xml:base="/swift/low-level/audio/avfoundation/2024/12/01/avaudioeffectnode-input-output.html"><![CDATA[<p>In my <a href="https://orjpap.github.io/swift/low-level/audio/avfoundation/2024/09/19/avAudioEffectNode.html">previous post</a>, I have come up with a simplistic implementation of an AVAudioEffectNode with a custom render block. At that time, I assumed a fixed setup with two channels and a sample rate of 44,100 Hz. However, a reader recently reached out, asking how to adapt this for an audio effect that converts stereo input to mono output. This inspired me to modify the <code>AVAudioEffectNode</code> class for greater flexibility.</p>
<h2 id="key-changes">Key Changes</h2>
<p>To accommodate different input and output configurations, I made the following updates:</p>
<ol>
<li><strong>Dynamic Bus Arrays</strong>: Instead of using fixed input and output busses, I implemented lazy-loaded bus arrays. This allows for more dynamic configuration:</li>
</ol>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">lazy</span> <span class="k">var</span> <span class="nv">inputBusArray</span><span class="p">:</span> <span class="kt">AUAudioUnitBusArray</span> <span class="o">=</span> <span class="p">{</span>
	<span class="k">let</span> <span class="nv">defaultAudioFormat</span> <span class="o">=</span> <span class="kt">AVAudioFormat</span><span class="p">(</span><span class="nv">standardFormatWithSampleRate</span><span class="p">:</span> <span class="mi">44100</span><span class="p">,</span> <span class="nv">channels</span><span class="p">:</span> <span class="mi">2</span><span class="p">)</span><span class="o">!</span>
	<span class="k">let</span> <span class="nv">inputBus</span> <span class="o">=</span> <span class="k">try!</span> <span class="kt">AUAudioUnitBus</span><span class="p">(</span><span class="nv">format</span><span class="p">:</span> <span class="n">defaultAudioFormat</span><span class="p">)</span>
	<span class="k">return</span> <span class="kt">AUAudioUnitBusArray</span><span class="p">(</span><span class="nv">audioUnit</span><span class="p">:</span> <span class="k">self</span><span class="p">,</span> <span class="nv">busType</span><span class="p">:</span> <span class="o">.</span><span class="n">input</span><span class="p">,</span> <span class="nv">busses</span><span class="p">:</span> <span class="p">[</span><span class="n">inputBus</span><span class="p">])</span>
<span class="p">}()</span>
<span class="kd">private</span> <span class="kd">lazy</span> <span class="k">var</span> <span class="nv">outputBusArray</span><span class="p">:</span> <span class="kt">AUAudioUnitBusArray</span> <span class="o">=</span> <span class="p">{</span>
	<span class="k">let</span> <span class="nv">defaultAudioFormat</span> <span class="o">=</span> <span class="kt">AVAudioFormat</span><span class="p">(</span><span class="nv">standardFormatWithSampleRate</span><span class="p">:</span> <span class="mi">44100</span><span class="p">,</span> <span class="nv">channels</span><span class="p">:</span> <span class="mi">2</span><span class="p">)</span><span class="o">!</span>
	<span class="k">let</span> <span class="nv">outputBus</span> <span class="o">=</span> <span class="k">try!</span> <span class="kt">AUAudioUnitBus</span><span class="p">(</span><span class="nv">format</span><span class="p">:</span> <span class="n">defaultAudioFormat</span><span class="p">)</span>
	<span class="k">return</span> <span class="kt">AUAudioUnitBusArray</span><span class="p">(</span><span class="nv">audioUnit</span><span class="p">:</span> <span class="k">self</span><span class="p">,</span> <span class="nv">busType</span><span class="p">:</span> <span class="o">.</span><span class="n">output</span><span class="p">,</span> <span class="nv">busses</span><span class="p">:</span> <span class="p">[</span><span class="n">outputBus</span><span class="p">])</span>
<span class="p">}()</span>
</code></pre></div></div>
<ol start="2">
<li><strong>Overriding Bus Properties</strong> needed for AUV3 implementation</li>
</ol>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="k">override</span> <span class="k">var</span> <span class="nv">inputBusses</span><span class="p">:</span> <span class="kt">AUAudioUnitBusArray</span> <span class="p">{</span>
	<span class="k">return</span> <span class="n">inputBusArray</span>
<span class="p">}</span>

<span class="kd">public</span> <span class="k">override</span> <span class="k">var</span> <span class="nv">outputBusses</span><span class="p">:</span> <span class="kt">AUAudioUnitBusArray</span> <span class="p">{</span>
	<span class="k">return</span> <span class="n">outputBusArray</span>
<span class="p">}</span>
</code></pre></div></div>
<p>For the full implementation, check out <a href="https://gist.github.com/orjpap/85a3d1029ff068516a4063d04ea5b8d8">this gist</a>.</p>
<h2 id="usage">Usage</h2>
<p>You can now easily change the input and output formats using:</p>
<ul>
<li><code>avAudioEffectNode.auAudioUnit.inputBusses.replaceBusses</code></li>
<li><code>avAudioEffectNode.auAudioUnit.outputBusses.replaceBusses</code></li>
</ul>
<p>Here's an example using the symclip node from my <a href="https://github.com/orjpap/AVAudioEffectNode-Example">previous example</a>:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">print</span><span class="p">(</span><span class="n">symClipNode</span><span class="o">.</span> <span class="nf">inputFormat</span> <span class="p">(</span><span class="nv">forBus</span><span class="p">:</span> <span class="mi">0</span><span class="p">))</span>
<span class="c1">// prints: &lt;AVAudioFormat 0x600002a85180: 2 ch, 44100 Hz, Float32, deinterleaved&gt;</span>

<span class="k">let</span> <span class="nv">audioFormat</span> <span class="o">=</span> <span class="kt">AVAudioFormat</span><span class="p">(</span><span class="nv">standardFormatWithSampleRate</span><span class="p">:</span> <span class="mi">48000</span><span class="p">,</span> <span class="nv">channels</span><span class="p">:</span> <span class="mi">1</span><span class="p">)</span><span class="o">!</span>
<span class="k">let</span> <span class="nv">inputBuss</span> <span class="o">=</span> <span class="k">try</span> <span class="kt">AUAudioUnitBus</span><span class="p">(</span><span class="nv">format</span><span class="p">:</span> <span class="n">audioFormat</span><span class="p">)</span>

<span class="n">symClipNode</span><span class="o">.</span><span class="n">auAudioUnit</span><span class="o">.</span><span class="n">inputBusses</span><span class="o">.</span><span class="nf">replaceBusses</span><span class="p">([</span><span class="n">inputBuss</span><span class="p">])</span>

<span class="nf">print</span><span class="p">(</span><span class="n">symClipNode</span><span class="o">.</span><span class="nf">inputFormat</span> <span class="p">(</span><span class="nv">forBus</span><span class="p">:</span> <span class="mi">0</span><span class="p">))</span>
<span class="c1">// prints: &lt;AVAudioFormat 0x600002a84d0: 1 ch, 48000 Hz, Float32, deinterleaved&gt;</span>
</code></pre></div></div>
<h2 id="bonus-byob-bring-your-own-buffers-input-pulling">Bonus: BYOB (Bring your own buffers) input pulling</h2>
<p>When the input and output have different buffer counts (2 in and 1 out in our reader's case) you have to BYOB.</p>
<p>Here's a sane (and not very Swifty) way of doing this:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">sumNode</span> <span class="o">=</span> <span class="kt">AVAudioEffectNode</span><span class="p">(</span><span class="nv">renderBlock</span><span class="p">:</span> <span class="p">{</span> <span class="n">actionFlags</span><span class="p">,</span> <span class="n">timestamp</span><span class="p">,</span> <span class="n">frameCount</span><span class="p">,</span> <span class="n">outputBusNumber</span><span class="p">,</span>
	<span class="n">outputData</span><span class="p">,</span> <span class="n">renderEvent</span><span class="p">,</span> <span class="n">pullInputBlock</span> <span class="o">-&gt;</span> <span class="kt">AUAudioUnitStatus</span> <span class="k">in</span>

	<span class="k">let</span> <span class="nv">bufferSizeBytes</span> <span class="o">=</span> <span class="kt">MemoryLayout</span><span class="o">&lt;</span><span class="kt">Float</span><span class="o">&gt;.</span><span class="n">size</span> <span class="o">*</span> <span class="kt">Int</span> <span class="p">(</span><span class="n">frameCount</span><span class="p">)</span>
	<span class="k">var</span> <span class="nv">inputBufferlist</span> <span class="o">=</span> <span class="kt">AudioBufferList</span><span class="o">.</span><span class="nf">allocate</span><span class="p">(</span><span class="nv">maximumBuffers</span><span class="p">:</span> <span class="mi">2</span><span class="p">)</span>

	<span class="n">inputBufferList</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="kt">AudioBuffer</span> <span class="p">(</span><span class="nv">mNumberChannels</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
									  <span class="nv">mDataByteSize</span><span class="p">:</span> <span class="kt">UInt32</span><span class="p">(</span><span class="n">bufferSizeBytes</span><span class="p">),</span>
									  <span class="nv">mData</span><span class="p">:</span> <span class="nf">malloc</span><span class="p">(</span><span class="n">bufferSizeBytes</span><span class="p">))</span>
	<span class="n">inputBufferList</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="kt">AudioBuffer</span> <span class="p">(</span><span class="nv">mNumberChannels</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
									  <span class="nv">mDataByteSize</span><span class="p">:</span> <span class="kt">UInt32</span><span class="p">(</span><span class="n">bufferSizeBytes</span><span class="p">),</span>
									  <span class="nv">mData</span><span class="p">:</span> <span class="nf">malloc</span><span class="p">(</span><span class="n">bufferSizeBytes</span><span class="p">))</span>
	<span class="c1">// Pull the audio from the input</span>
	<span class="k">let</span> <span class="nv">inputStatus</span> <span class="o">=</span> <span class="nf">pullInputBlock</span><span class="p">?(</span><span class="n">actionFlags</span><span class="p">,</span> <span class="n">timestamp</span><span class="p">,</span> <span class="n">frameCount</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">inputBufferList</span><span class="o">.</span><span class="n">unsafeMutablePointer</span><span class="p">)</span>
	
	<span class="k">if</span> <span class="n">inputStatus</span> <span class="o">!=</span> <span class="n">noErr</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">inputStatus</span> <span class="p">??</span> <span class="kt">KAudioUnitErr_FailedInitialization</span>
	<span class="p">}</span>

	<span class="k">let</span> <span class="nv">ablPointer</span> <span class="o">=</span> <span class="kt">UnsafeMutableAudioBufferListPointer</span><span class="p">(</span><span class="n">outputData</span><span class="p">)</span>
	<span class="k">for</span> <span class="n">buffer</span> <span class="k">in</span> <span class="n">ablPointer</span> <span class="p">{</span>
		<span class="c1">// do your summing here</span>
		<span class="k">let</span> <span class="nv">input</span> <span class="o">=</span> <span class="kt">UnsafePointer</span><span class="o">&lt;</span><span class="kt">Float</span><span class="o">&gt;</span><span class="p">(</span><span class="n">inputBufferList</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">mData</span><span class="o">!.</span><span class="nf">assumingMemoryBound</span><span class="p">(</span><span class="nv">to</span><span class="p">:</span> <span class="kt">Float</span><span class="o">.</span><span class="k">self</span><span class="p">))</span>
		<span class="o">...</span>
	<span class="p">}</span>
<span class="err">｝</span>
</code></pre></div></div>
<p>Since you allocated you are now also responsible for freeing when you are done with the block:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">buffer</span> <span class="k">in</span> <span class="n">inputBufferList</span> <span class="p">{</span>
	<span class="nf">free</span><span class="p">(</span><span class="n">buffer</span><span class="o">.</span><span class="n">mData</span><span class="p">)</span>
<span class="p">}</span>
<span class="nf">free</span><span class="p">(</span><span class="n">inputBufferList</span><span class="o">.</span><span class="n">unsafeMutablePointer</span><span class="p">)</span>
</code></pre></div></div>
<p>Unfortunately some of those C-APIs don't translate well to Swift and can be hard to use even when you know what you are doing.</p>
<p>Feel free to <a href="mailto:orjpap@gmail.com">contact me</a> for tips, feedback, opinions or sending me your cool audio effects.</p>
<p>Thank you for reading!</p>]]></content><author><name>Orestis Papadopoulos</name></author><category term="Swift" /><category term="Low-level" /><category term="Audio" /><category term="AVFoundation" /><summary type="html"><![CDATA[In my previous post, I have come up with a simplistic implementation of an AVAudioEffectNode with a custom render block. At that time, I assumed a fixed setup with two channels and a sample rate of 44,100 Hz. However, a reader recently reached out, asking how to adapt this for an audio effect that converts stereo input to mono output. This inspired me to modify the AVAudioEffectNode class for greater flexibility.]]></summary></entry><entry><title type="html">AVAudioEffectNode: painless low level audio effects written in Swift</title><link href="/swift/low-level/audio/avfoundation/2024/09/19/avAudioEffectNode.html" rel="alternate" type="text/html" title="AVAudioEffectNode: painless low level audio effects written in Swift" /><published>2024-09-19T09:33:36+03:00</published><updated>2024-09-19T09:33:36+03:00</updated><id>/swift/low-level/audio/avfoundation/2024/09/19/avAudioEffectNode</id><content type="html" xml:base="/swift/low-level/audio/avfoundation/2024/09/19/avAudioEffectNode.html"><![CDATA[<p>In a <a href="https://orjpap.github.io/swift/real-time/audio/avfoundation/2020/06/19/avaudiosourcenode.html">previous post</a>, I covered two AVFoundation nodes that can generate sound or tap into the output of an existing node. If you experiment with them, you'll quickly realize:</p>
<ol>
<li><strong>AVAudioSourceNode</strong> has 0 inputs and 1 output.</li>
<li><strong>AVAudioSinkNode</strong> has 1 input and 0 outputs.</li>
</ol>
<p>This means we can't use these nodes to create audio effects directly, since an audio effect needs (at least) 1 input and 1 output.</p>
<p>For creating audio effects, we typically use Audio Units. The AUv3 standard is built on the App Extensions model, meaning your plug-in is an extension contained within an app. Apple provides examples on how to do this, but they are often full of boilerplate and can be challenging to the uninitiated—where's the fun in that, right?</p>
<p>And by fun, I mean fun like <a href="https://github.com/alexbw/novocaine">Novocaine</a>, an Objective-C library that &quot;takes the pain out of high-performance audio on iOS and macOS.&quot; Following a similar approach, I'll guide you through the simplest way I’ve found to create a user-friendly API for building audio effects in Swift using <strong>AVFoundation</strong>.</p>
<h2 id="audiounit-auaudiounit-avaudiounit-send-help">AudioUnit, AUAudioUnit, AVAudioUnit (Send Help!)</h2>
<p>Now, let's dive into creating our own <code>AVAudioEffectNode</code>. The API should look something like this:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">myEffectNode</span> <span class="o">=</span> <span class="kt">AVAudioEffectNode</span><span class="p">(</span><span class="nv">renderBlock</span><span class="p">:</span> <span class="p">{</span> <span class="o">--</span> <span class="n">our</span> <span class="n">render</span> <span class="n">block</span> <span class="o">--</span><span class="p">})</span>
</code></pre></div></div>
<p>Since we’re using <strong>AVFoundation</strong>, we need to create an <code>AVAudioNode</code> that can attach to the engine. This is where <code>AVAudioUnit</code> comes in, acting as a wrapper for Audio Units within <strong>AVFoundation</strong>. There are specialized subclasses like <code>AVAudioUnitEffect</code>, which we’ll be using later.</p>
<p>If you're new to this, a good starting point is the <code>AUComponent.h</code> header file in Xcode (just Cmd+Click on <code>AudioUnit</code> to access it). Here’s a quick summary:</p>
<ol>
<li>
<p>Audio Units contain render blocks that handle the audio processing.</p>
</li>
<li>
<p>You create your own Audio Unit by subclassing <code>AUAudioUnit</code> (since <code>AudioUnit</code> is just a typealias).</p>
</li>
<li>
<p>An <code>AudioComponentDescription</code> is used to describe the unit, which is later instantiated.</p>
</li>
</ol>
<h3 id="audiocomponentdescription">AudioComponentDescription</h3>
<p>Here's how to define an <strong>AudioComponentDescription</strong> for our custom effect:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">AVFoundation</span>

<span class="kd">extension</span> <span class="kt">AudioComponentDescription</span> <span class="p">{</span>
    <span class="kd">static</span> <span class="k">let</span> <span class="nv">AVAudioEffectNodeAudioUnit</span> <span class="o">=</span> <span class="kt">AudioComponentDescription</span><span class="p">(</span>
        <span class="nv">componentType</span><span class="p">:</span> <span class="n">kAudioUnitType_Effect</span><span class="p">,</span>
        <span class="nv">componentSubType</span><span class="p">:</span> <span class="nf">fourCharCodeFrom</span><span class="p">(</span><span class="s">"avae"</span><span class="p">),</span> <span class="c1">// provide your own</span>
        <span class="nv">componentManufacturer</span><span class="p">:</span> <span class="nf">fourCharCodeFrom</span><span class="p">(</span><span class="s">"orjp"</span><span class="p">),</span> <span class="c1">// provide your own</span>
        <span class="nv">componentFlags</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
        <span class="nv">componentFlagsMask</span><span class="p">:</span> <span class="mi">0</span>
    <span class="p">)</span>
<span class="p">}</span>

<span class="kd">func</span> <span class="nf">fourCharCodeFrom</span><span class="p">(</span><span class="n">_</span> <span class="nv">string</span> <span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">FourCharCode</span> <span class="p">{</span>
    <span class="nf">assert</span><span class="p">(</span><span class="n">string</span><span class="o">.</span><span class="n">count</span> <span class="o">==</span> <span class="mi">4</span><span class="p">,</span> <span class="s">"String length must be 4"</span><span class="p">)</span>
    <span class="k">var</span> <span class="nv">result</span> <span class="p">:</span> <span class="kt">FourCharCode</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">char</span> <span class="k">in</span> <span class="n">string</span><span class="o">.</span><span class="n">utf16</span> <span class="p">{</span>
        <span class="n">result</span> <span class="o">=</span> <span class="p">(</span><span class="n">result</span> <span class="o">&lt;&lt;</span> <span class="mi">8</span><span class="p">)</span> <span class="o">+</span> <span class="kt">FourCharCode</span><span class="p">(</span><span class="n">char</span><span class="p">)</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">result</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In this example, we specify the <code>componentType</code> as <code>kAudioUnitType_Effect</code> because we’re building an effect. You also need to define custom four-character codes for <code>SubType</code> and <code>Manufacturer</code>. I’ve added a helper function to simplify that.</p>
<blockquote>
<p><strong>Note:</strong> If you're debugging a macOS app and encounter the error <strong>Code=-3000 &quot;invalidComponentID&quot;</strong>, set the <code>componentFlags</code> to <code>AudioComponentFlags.sandboxSafe.rawValue</code>.</p>
</blockquote>
<h3 id="custom-auaudiounit">Custom AUAudioUnit</h3>
<p>Next, we subclass <code>AUAudioUnit</code> to create <code>AVAudioEffectNodeAudioUnit</code>, this is our custom Audio Unit:</p>
<ol>
<li>We’ll need to override the <code>internalRenderBlock</code> to pass in our custom render logic.</li>
<li>We’ll also need to define one input and one output bus by overriding <code>inputBusses</code> and <code>outputBusses</code>.</li>
</ol>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="kt">AVAudioEffectNodeAudioUnit</span><span class="p">:</span> <span class="kt">AUAudioUnit</span> <span class="p">{</span>
    <span class="k">let</span> <span class="nv">inputBus</span><span class="p">:</span> <span class="kt">AUAudioUnitBus</span>
    <span class="k">let</span> <span class="nv">outputBus</span><span class="p">:</span> <span class="kt">AUAudioUnitBus</span>

    <span class="k">var</span> <span class="nv">_internalRenderBlock</span><span class="p">:</span> <span class="kt">AUInternalRenderBlock</span>

    <span class="kd">public</span> <span class="k">override</span> <span class="nf">init</span><span class="p">(</span>
        <span class="nv">componentDescription</span><span class="p">:</span> <span class="kt">AudioComponentDescription</span><span class="p">,</span>
        <span class="nv">options</span><span class="p">:</span> <span class="kt">AudioComponentInstantiationOptions</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="p">)</span> <span class="k">throws</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">audioFormat</span> <span class="o">=</span> <span class="kt">AVAudioFormat</span><span class="p">(</span><span class="nv">standardFormatWithSampleRate</span><span class="p">:</span> <span class="mi">44100</span><span class="p">,</span> <span class="nv">channels</span><span class="p">:</span> <span class="mi">2</span><span class="p">)</span><span class="o">!</span>

        <span class="n">inputBus</span> <span class="o">=</span> <span class="k">try</span> <span class="kt">AUAudioUnitBus</span><span class="p">(</span><span class="nv">format</span><span class="p">:</span> <span class="n">audioFormat</span><span class="p">)</span>
        <span class="n">outputBus</span> <span class="o">=</span> <span class="k">try</span> <span class="kt">AUAudioUnitBus</span><span class="p">(</span><span class="nv">format</span><span class="p">:</span> <span class="n">audioFormat</span><span class="p">)</span>

        <span class="n">_internalRenderBlock</span> <span class="o">=</span> <span class="p">{</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="k">in</span>
            <span class="k">return</span> <span class="n">kAudioUnitErr_Uninitialized</span>
        <span class="p">}</span>

        <span class="k">try</span> <span class="k">super</span><span class="o">.</span><span class="nf">init</span><span class="p">(</span><span class="nv">componentDescription</span><span class="p">:</span> <span class="n">componentDescription</span><span class="p">,</span> <span class="nv">options</span><span class="p">:</span> <span class="n">options</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="kd">public</span> <span class="k">override</span> <span class="k">var</span> <span class="nv">inputBusses</span><span class="p">:</span> <span class="kt">AUAudioUnitBusArray</span> <span class="p">{</span>
        <span class="k">return</span> <span class="kt">AUAudioUnitBusArray</span><span class="p">(</span><span class="nv">audioUnit</span><span class="p">:</span> <span class="k">self</span><span class="p">,</span> <span class="nv">busType</span><span class="p">:</span> <span class="o">.</span><span class="n">input</span><span class="p">,</span> <span class="nv">busses</span><span class="p">:</span> <span class="p">[</span><span class="n">inputBus</span><span class="p">])</span>
    <span class="p">}</span>


    <span class="kd">public</span> <span class="k">override</span> <span class="k">var</span> <span class="nv">outputBusses</span><span class="p">:</span> <span class="kt">AUAudioUnitBusArray</span> <span class="p">{</span>
        <span class="k">return</span> <span class="kt">AUAudioUnitBusArray</span><span class="p">(</span><span class="nv">audioUnit</span><span class="p">:</span> <span class="k">self</span><span class="p">,</span> <span class="nv">busType</span><span class="p">:</span> <span class="o">.</span><span class="n">output</span><span class="p">,</span> <span class="nv">busses</span><span class="p">:</span> <span class="p">[</span><span class="n">outputBus</span><span class="p">])</span>
    <span class="p">}</span>

    <span class="kd">public</span> <span class="k">override</span> <span class="k">var</span> <span class="nv">internalRenderBlock</span><span class="p">:</span> <span class="kt">AUInternalRenderBlock</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">_internalRenderBlock</span>
    <span class="p">}</span>
<span class="p">}</span>

</code></pre></div></div>
<h3 id="time-for-the-glue">Time for the glue.</h3>
<p>Now that we’ve created the core, let’s glue everything together by creating an <code>AVAudioEffectNode</code> class. This will inherit from <code>AVAudioUnitEffect</code>, and we’ll write a convenience initializer that allows us to pass in a render block—much like the <code>AVAudioSourceNode</code> API.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="kt">AVAudioEffectNode</span><span class="p">:</span> <span class="kt">AVAudioUnitEffect</span> <span class="p">{</span>
    <span class="kd">convenience</span> <span class="nf">init</span><span class="p">(</span><span class="nv">renderBlock</span><span class="p">:</span> <span class="kd">@escaping</span> <span class="kt">AUInternalRenderBlock</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">AUAudioUnit</span><span class="o">.</span><span class="nf">registerSubclass</span><span class="p">(</span><span class="kt">AVAudioEffectNodeAudioUnit</span><span class="o">.</span><span class="k">self</span><span class="p">,</span>
                                     <span class="nv">as</span><span class="p">:</span> <span class="o">.</span><span class="kt">AVAudioEffectNodeAudioUnit</span><span class="p">,</span>
                                     <span class="nv">name</span><span class="p">:</span> <span class="s">"AVAudioEffectNode"</span><span class="p">,</span>
                                     <span class="nv">version</span><span class="p">:</span> <span class="mi">0</span><span class="p">)</span>

        <span class="k">self</span><span class="o">.</span><span class="nf">init</span><span class="p">(</span><span class="nv">audioComponentDescription</span><span class="p">:</span> <span class="o">.</span><span class="kt">AVAudioEffectNodeAudioUnit</span><span class="p">)</span>

        <span class="k">let</span> <span class="nv">audioEffectAudioUnit</span> <span class="o">=</span> <span class="k">self</span><span class="o">.</span><span class="n">auAudioUnit</span> <span class="k">as!</span> <span class="kt">AVAudioEffectNodeAudioUnit</span>
        <span class="n">audioEffectAudioUnit</span><span class="o">.</span><span class="n">_internalRenderBlock</span> <span class="o">=</span> <span class="n">renderBlock</span>
	 <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<ol>
<li>First, we register our custom <code>AUAudioUnit</code> using the <strong>AudioComponentDescription</strong> we defined earlier.</li>
<li>Next, we initialize the <code>AVAudioUnitEffect</code> using its inherited initializer.</li>
<li>Finally, we retrieve the <code>auAudioUnit</code>, cast it to our custom subclass, and pass the render block.</li>
</ol>
<h2 id="example-symmetrical-clipping-effect">Example: Symmetrical Clipping Effect</h2>
<p>Here’s an example of how to implement a <strong>symmetrical clipping</strong> effect using <code>AVAudioEffectNode</code>. Symmetrical clipping is commonly used in overdrive simulations to clip both positive and negative waveform peaks evenly.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">AVFoundation</span>

<span class="k">let</span> <span class="nv">symClipThreshold</span><span class="p">:</span> <span class="kt">Float</span> <span class="o">=</span> <span class="mf">1.0</span><span class="o">/</span><span class="mf">3.0</span> <span class="c1">// higher denominator &gt; more clipping</span>

<span class="k">let</span> <span class="nv">symClipNode</span> <span class="o">=</span> <span class="kt">AVAudioEffectNode</span><span class="p">(</span><span class="nv">renderBlock</span><span class="p">:</span> <span class="p">{</span> <span class="n">actionFlags</span><span class="p">,</span> <span class="n">timestamp</span><span class="p">,</span> <span class="n">frameCount</span><span class="p">,</span> <span class="n">outputBusNumber</span><span class="p">,</span> <span class="n">outputData</span><span class="p">,</span> <span class="n">renderEvent</span><span class="p">,</span> <span class="n">pullInputBlock</span> <span class="o">-&gt;</span> <span class="kt">AUAudioUnitStatus</span> <span class="k">in</span>

    <span class="c1">// Pull the audio from the input</span>
    <span class="k">let</span> <span class="nv">inputStatus</span> <span class="o">=</span> <span class="nf">pullInputBlock</span><span class="p">?(</span><span class="n">actionFlags</span><span class="p">,</span> <span class="n">timestamp</span><span class="p">,</span> <span class="n">frameCount</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">outputData</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">inputStatus</span> <span class="o">!=</span> <span class="n">noErr</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">inputStatus</span> <span class="p">??</span> <span class="n">kAudioUnitErr_FailedInitialization</span>
    <span class="p">}</span>

    <span class="k">let</span> <span class="nv">ablPointer</span> <span class="o">=</span> <span class="kt">UnsafeMutableAudioBufferListPointer</span><span class="p">(</span><span class="n">outputData</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">buffer</span> <span class="k">in</span> <span class="n">ablPointer</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">input</span> <span class="o">=</span> <span class="kt">UnsafePointer</span><span class="o">&lt;</span><span class="kt">Float</span><span class="o">&gt;</span><span class="p">(</span><span class="n">buffer</span><span class="o">.</span><span class="n">mData</span><span class="o">!.</span><span class="nf">assumingMemoryBound</span><span class="p">(</span><span class="nv">to</span><span class="p">:</span> <span class="kt">Float</span><span class="o">.</span><span class="k">self</span><span class="p">))</span>
        <span class="k">let</span> <span class="nv">outputBuffer</span> <span class="o">=</span> <span class="kt">UnsafeMutablePointer</span><span class="o">&lt;</span><span class="kt">Float</span><span class="o">&gt;</span><span class="p">(</span><span class="n">buffer</span><span class="o">.</span><span class="n">mData</span><span class="o">!.</span><span class="nf">assumingMemoryBound</span><span class="p">(</span><span class="nv">to</span><span class="p">:</span> <span class="kt">Float</span><span class="o">.</span><span class="k">self</span><span class="p">))</span>
        <span class="k">let</span> <span class="nv">processed</span> <span class="o">=</span> <span class="nf">symClip</span><span class="p">(</span><span class="nv">input</span><span class="p">:</span> <span class="n">input</span><span class="p">,</span> <span class="nv">count</span><span class="p">:</span> <span class="kt">Int</span><span class="p">(</span><span class="n">frameCount</span><span class="p">))</span>
        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..&lt;</span><span class="kt">Int</span><span class="p">(</span><span class="n">frameCount</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">outputBuffer</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">processed</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">noErr</span>
<span class="p">})</span>

<span class="c1">// "Overdrive" simlation with symmetrical clipping from DAFX (2011) translated to Swift</span>
<span class="c1">// Author: Dutilleux, ZΓΆlzer</span>
<span class="c1">// Symmetrical clipping clips both positive and negative amplitude peaks of a waveform evenly</span>
<span class="kd">func</span> <span class="nf">symClip</span><span class="p">(</span><span class="nv">input</span><span class="p">:</span> <span class="kt">UnsafePointer</span><span class="o">&lt;</span><span class="kt">Float</span><span class="o">&gt;</span><span class="p">,</span> <span class="nv">count</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="kt">Float</span><span class="p">]</span> <span class="p">{</span>
    <span class="k">var</span> <span class="nv">output</span> <span class="o">=</span> <span class="p">[</span><span class="kt">Float</span><span class="p">](</span><span class="nv">repeating</span><span class="p">:</span> <span class="mf">0.0</span><span class="p">,</span> <span class="nv">count</span><span class="p">:</span> <span class="n">count</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..&lt;</span><span class="n">count</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">x</span> <span class="o">=</span> <span class="n">input</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
        <span class="k">if</span> <span class="nf">abs</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">symClipThreshold</span> <span class="p">{</span>
            <span class="n">output</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="n">x</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="nf">abs</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="n">symClipThreshold</span> <span class="o">&amp;&amp;</span> <span class="nf">abs</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="n">symClipThreshold</span> <span class="p">{</span>
            <span class="k">if</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="p">{</span>
                <span class="n">output</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mf">3.0</span> <span class="o">-</span> <span class="nf">pow</span><span class="p">((</span><span class="mf">2.0</span> <span class="o">-</span> <span class="n">x</span> <span class="o">*</span> <span class="mf">3.0</span><span class="p">),</span> <span class="mf">2.0</span><span class="p">))</span> <span class="o">/</span> <span class="mf">3.0</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">output</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span><span class="p">(</span><span class="mf">3.0</span> <span class="o">-</span> <span class="nf">pow</span><span class="p">((</span><span class="mf">2.0</span> <span class="o">-</span> <span class="nf">abs</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">*</span> <span class="mf">3.0</span><span class="p">),</span> <span class="mf">2.0</span><span class="p">))</span> <span class="o">/</span> <span class="mf">3.0</span>
            <span class="p">}</span>
        <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="nf">abs</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mf">2.0</span> <span class="o">*</span> <span class="n">symClipThreshold</span> <span class="p">{</span>
            <span class="k">if</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="p">{</span>
                <span class="n">output</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mf">1.0</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">output</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span><span class="mf">1.0</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">output</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="putting-the-nodes-together">Putting the Nodes Together</h3>
<p>You can now connect any kind of <code>AVAudioEngineNode</code> to your shiny new audio effect:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">engine</span> <span class="o">=</span> <span class="kt">AVAudioEngine</span><span class="p">()</span>

<span class="n">engine</span><span class="o">.</span><span class="nf">attach</span><span class="p">(</span><span class="n">sineWaveNode</span><span class="p">)</span>
<span class="n">engine</span><span class="o">.</span><span class="nf">attach</span><span class="p">(</span><span class="n">symClipNode</span><span class="p">)</span>

<span class="n">engine</span><span class="o">.</span><span class="nf">connect</span><span class="p">(</span><span class="n">sineWaveNode</span><span class="p">,</span> <span class="nv">to</span><span class="p">:</span> <span class="n">symClipNode</span><span class="p">,</span> <span class="nv">format</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>
<span class="n">engine</span><span class="o">.</span><span class="nf">connect</span><span class="p">(</span><span class="n">symClipNode</span><span class="p">,</span> <span class="nv">to</span><span class="p">:</span> <span class="n">engine</span><span class="o">.</span><span class="n">mainMixerNode</span><span class="p">,</span> <span class="nv">format</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>

<span class="n">engine</span><span class="o">.</span><span class="n">mainMixerNode</span><span class="o">.</span><span class="n">volume</span> <span class="o">=</span> <span class="mf">0.4</span>

<span class="k">try!</span> <span class="n">engine</span><span class="o">.</span><span class="nf">start</span><span class="p">()</span>
<span class="kt">CFRunLoopRun</span><span class="p">()</span>
<span class="n">engine</span><span class="o">.</span><span class="nf">stop</span><span class="p">()</span>

</code></pre></div></div>
<h2 id="coda">Coda</h2>
<p>All in all, combining a source node, sink node, and effect node creates a robust and flexible API for low-level audio processing and generation with AVFoundation. I'm excited to see where AVFoundation is headed and hopeful that future updates will bring even more user-friendly Swift APIs for audio development.</p>
<p>You can find the <a href="https://github.com/orjpap/AVAudioEffectNode-Example">full example</a> as an Xcode project on my github.</p>
<p>Feel free to <a href="mailto:orjpap@gmail.com">contact me</a> for tips, feedback, opinions or sending me your cool audio effects.</p>
<p>Thank you for reading!</p>]]></content><author><name>Orestis Papadopoulos</name></author><category term="Swift" /><category term="Low-level" /><category term="Audio" /><category term="AVFoundation" /><summary type="html"><![CDATA[In a previous post, I covered two AVFoundation nodes that can generate sound or tap into the output of an existing node. If you experiment with them, you'll quickly realize:]]></summary></entry><entry><title type="html">CaseSequencable: Put your enums in order</title><link href="/swift/caseiterable/protocols/2022/05/25/casesequencable.html" rel="alternate" type="text/html" title="CaseSequencable: Put your enums in order" /><published>2022-05-25T18:33:36+03:00</published><updated>2022-05-25T18:33:36+03:00</updated><id>/swift/caseiterable/protocols/2022/05/25/casesequencable</id><content type="html" xml:base="/swift/caseiterable/protocols/2022/05/25/casesequencable.html"><![CDATA[<p>Enums are often used to model states. If we want to move to the next state (in order of declaration) we have to do the switch dance:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">enum</span> <span class="kt">MyState</span> <span class="p">{</span>
  <span class="k">case</span> <span class="n">sleeping</span>
  <span class="k">case</span> <span class="n">working</span>
  <span class="k">case</span> <span class="n">chilling</span>
<span class="p">}</span>

<span class="k">var</span> <span class="nv">myState</span><span class="p">:</span> <span class="kt">MyState</span> <span class="o">=</span> <span class="o">.</span><span class="n">sleeping</span>

<span class="kd">func</span> <span class="nf">nextState</span><span class="p">()</span> <span class="p">{</span>
	<span class="k">switch</span> <span class="n">myState</span> <span class="p">{</span>
    <span class="k">case</span> <span class="nv">sleeping</span><span class="p">:</span>
    <span class="o">....</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>By conforming an enum to<code>CaseIterable</code> type, we can access a collection of all of the type’s cases by using the type’s <code>allCases</code> property. The <code>allCases</code> property is compiler synthesized (for enums that don’t have associated values) and provides the cases in order of their declaration.</p>
<p>We can implement a simple protocol named <code>CaseSequencable</code> which inherits from the <code>CaseIterable</code> protocol:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">protocol</span> <span class="kt">CaseSequencable</span><span class="p">:</span> <span class="kt">CaseIterable</span><span class="p">,</span> <span class="kt">Equatable</span> <span class="p">{</span>
    <span class="k">var</span> <span class="nv">nextCase</span><span class="p">:</span> <span class="k">Self</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span>
<span class="p">}</span>

<span class="kd">extension</span> <span class="kt">CaseSequencable</span> <span class="p">{</span>
    <span class="k">var</span> <span class="nv">nextCase</span><span class="p">:</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="c1">// allCases is compiler synthesized (for enums without associated values)</span>
        <span class="c1">// there is no possible way for self to not exist in allCases</span>
        <span class="c1">// if you manually conform to CaseIterable it will crash :D</span>
        <span class="k">let</span> <span class="nv">selfIndex</span> <span class="o">=</span> <span class="k">Self</span><span class="o">.</span><span class="n">allCases</span><span class="o">.</span><span class="nf">firstIndex</span><span class="p">(</span><span class="nv">of</span><span class="p">:</span><span class="k">self</span><span class="p">)</span><span class="o">!</span>

        <span class="k">let</span> <span class="nv">nextIndex</span> <span class="o">=</span> <span class="k">Self</span><span class="o">.</span><span class="n">allCases</span><span class="o">.</span><span class="nf">index</span><span class="p">(</span><span class="nv">after</span><span class="p">:</span> <span class="n">selfIndex</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">nextIndex</span> <span class="o">==</span> <span class="k">Self</span><span class="o">.</span><span class="n">allCases</span><span class="o">.</span><span class="n">endIndex</span> <span class="p">{</span>
            <span class="k">return</span> <span class="k">Self</span><span class="o">.</span><span class="n">allCases</span><span class="p">[</span><span class="k">Self</span><span class="o">.</span><span class="n">allCases</span><span class="o">.</span><span class="n">startIndex</span><span class="p">]</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">return</span> <span class="k">Self</span><span class="o">.</span><span class="n">allCases</span><span class="p">[</span><span class="n">nextIndex</span><span class="p">]</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And use it in the following way:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">enum</span> <span class="kt">MyState</span><span class="p">:</span> <span class="kt">CaseSequencable</span> <span class="p">{</span>
  <span class="k">case</span> <span class="n">sleeping</span>
  <span class="k">case</span> <span class="n">working</span>
  <span class="k">case</span> <span class="n">chilling</span>
<span class="p">}</span>

<span class="k">var</span> <span class="nv">myState</span><span class="p">:</span> <span class="kt">MyState</span> <span class="o">=</span> <span class="o">.</span><span class="n">sleeping</span>

<span class="n">myState</span> <span class="c1">// .sleeping</span>
<span class="n">myState</span><span class="o">.</span><span class="n">next</span> <span class="c1">// .working</span>
<span class="n">myState</span><span class="o">.</span><span class="n">next</span><span class="o">.</span><span class="n">next</span> <span class="c1">// .chilling</span>
<span class="n">myState</span><span class="o">.</span><span class="n">next</span><span class="o">.</span><span class="n">next</span><span class="o">.</span><span class="n">next</span> <span class="c1">// .sleeping (loops back to the first case)</span>
</code></pre></div></div>
<p>Feel free to <a href="mailto:orjpap@gmail.com">contact me</a> or tweet to me on <a href="https://twitter.com/orjpap">Twitter</a> for tips, feedback, opinions.</p>
<p>Thank you for reading!</p>]]></content><author><name>Orestis Papadopoulos</name></author><category term="Swift" /><category term="CaseIterable" /><category term="Protocols" /><summary type="html"><![CDATA[Enums are often used to model states. If we want to move to the next state (in order of declaration) we have to do the switch dance:]]></summary></entry><entry><title type="html">UserDefaultsPersistable: Save and Load any struct to/from UserDefaults</title><link href="/swift/userdefaults/ios/protocols/2021/10/10/userdefaultspersistable.html" rel="alternate" type="text/html" title="UserDefaultsPersistable: Save and Load any struct to/from UserDefaults" /><published>2021-10-10T18:33:36+03:00</published><updated>2021-10-10T18:33:36+03:00</updated><id>/swift/userdefaults/ios/protocols/2021/10/10/userdefaultspersistable</id><content type="html" xml:base="/swift/userdefaults/ios/protocols/2021/10/10/userdefaultspersistable.html"><![CDATA[<p>The user’s defaults database is a key-value store that let’s you persist data across app launches. It is meant to be used to store user preferences. Using the <code>Codeable</code> protocol and a <code>JSONEncoder</code> you can very easily convert Swift types to JSON data in order to store them.</p>
<h2 id="saveload-codeable-structs">Save/Load Codeable structs</h2>
<p>To save data into <code>UserDefaults</code> you must first encode it as JSON, and then save it using a specified key like this:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">Settings</span><span class="p">:</span> <span class="kt">Codeable</span> <span class="p">{</span>
  <span class="o">...</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">userSettings</span> <span class="o">=</span> <span class="kt">Settings</span><span class="p">()</span>

<span class="k">let</span> <span class="nv">encoder</span> <span class="o">=</span> <span class="kt">JSONEncoder</span><span class="p">()</span>
<span class="k">if</span> <span class="k">let</span> <span class="nv">encoded</span> <span class="o">=</span> <span class="k">try</span><span class="p">?</span> <span class="n">encoder</span><span class="o">.</span><span class="nf">encode</span><span class="p">(</span><span class="n">userSettings</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">UserDefaults</span><span class="o">.</span><span class="n">standard</span><span class="o">.</span><span class="nf">set</span><span class="p">(</span><span class="n">encoded</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="s">"archiveKey"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Then you can load it like this:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="k">let</span> <span class="nv">savedSettingsData</span> <span class="o">=</span> <span class="kt">UserDefaults</span><span class="o">.</span><span class="n">standard</span><span class="o">.</span><span class="nf">object</span><span class="p">(</span><span class="nv">forKey</span><span class="p">:</span> <span class="s">"archiveKey"</span><span class="p">)</span> <span class="k">as?</span> <span class="kt">Data</span> <span class="k">else</span> <span class="p">{</span>
    <span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
    <span class="k">let</span> <span class="nv">loadedSettings</span> <span class="o">=</span> <span class="k">try</span><span class="p">?</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">Settings</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">savedSettingsData</span><span class="p">)</span> <span class="c1">// Settings?</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="reusability">Reusability</h2>
<p>Using Swift protocols and <a href="https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID280">protocol inheritance</a>, we can define a<code>UserDefaultsPersistable</code> protocol:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">protocol</span> <span class="kt">DefaultInitializable</span> <span class="p">{</span>
  <span class="nf">init</span><span class="p">()</span>
<span class="p">}</span>

<span class="kd">protocol</span> <span class="kt">UserDefaultsPersistable</span><span class="p">:</span> <span class="kt">Codable</span><span class="p">,</span> <span class="kt">DefaultInitializable</span> <span class="p">{</span>
    <span class="kd">static</span> <span class="k">var</span> <span class="nv">key</span><span class="p">:</span> <span class="kt">String</span> <span class="p">{</span><span class="k">get</span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>We also defined another protocol called <code>DefaultInitializable</code> for types than can be initialized with a default value using a default initializer. The default value will be used in cases where we’re looking for the specific type in <code>UserDefaults</code> and it does not exist.</p>
<p>In order to provide a default implementation of <code>save</code> and <code>load</code> functions we will also create a <code>UserDefaultsPersister</code>:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">UserDefaultsPersister</span><span class="o">&lt;</span><span class="kt">A</span><span class="p">:</span> <span class="kt">UserDefaultsPersistable</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="kd">static</span> <span class="kd">func</span> <span class="nf">save</span><span class="p">(</span><span class="n">_</span> <span class="nv">value</span><span class="p">:</span> <span class="kt">A</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">encoder</span> <span class="o">=</span> <span class="kt">JSONEncoder</span><span class="p">()</span>
        <span class="k">if</span> <span class="k">let</span> <span class="nv">encoded</span> <span class="o">=</span> <span class="k">try</span><span class="p">?</span> <span class="n">encoder</span><span class="o">.</span><span class="nf">encode</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span>
            <span class="kt">UserDefaults</span><span class="o">.</span><span class="n">standard</span><span class="o">.</span><span class="nf">set</span><span class="p">(</span><span class="n">encoded</span><span class="p">,</span> <span class="nv">forKey</span><span class="p">:</span> <span class="kt">A</span><span class="o">.</span><span class="n">key</span><span class="p">)</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kd">static</span> <span class="kd">func</span> <span class="nf">load</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">A</span> <span class="p">{</span>
        <span class="k">guard</span> <span class="k">let</span> <span class="nv">savedSettingsData</span> <span class="o">=</span> <span class="kt">UserDefaults</span><span class="o">.</span><span class="n">standard</span><span class="o">.</span><span class="nf">object</span><span class="p">(</span><span class="nv">forKey</span><span class="p">:</span> <span class="kt">A</span><span class="o">.</span><span class="n">key</span><span class="p">)</span> <span class="k">as?</span> <span class="kt">Data</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kt">A</span><span class="p">()</span>
        <span class="p">}</span>

        <span class="k">let</span> <span class="nv">decoder</span> <span class="o">=</span> <span class="kt">JSONDecoder</span><span class="p">()</span>
        <span class="k">let</span> <span class="nv">loadedSettings</span> <span class="o">=</span> <span class="k">try</span><span class="p">?</span> <span class="n">decoder</span><span class="o">.</span><span class="nf">decode</span><span class="p">(</span><span class="kt">A</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">savedSettingsData</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">loadedSettings</span> <span class="p">??</span> <span class="kt">A</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And provide the default implementations for <code>UserDefaultsPersistable</code> protocol:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">extension</span> <span class="kt">UserDefaultsPersistable</span> <span class="p">{</span>
    <span class="kd">func</span> <span class="nf">save</span><span class="p">()</span> <span class="p">{</span>
        <span class="kt">UserDefaultsPersister</span><span class="o">.</span><span class="nf">save</span><span class="p">(</span><span class="k">self</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="kd">static</span> <span class="kd">func</span> <span class="nf">load</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="k">return</span> <span class="kt">UserDefaultsPersister</span><span class="o">.</span><span class="nf">load</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="usage">Usage</h2>
<p>For example, if you want to persist your app’s Audio settings:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">AudioPreferences</span><span class="p">:</span> <span class="kt">UserDefaultsPersistable</span> <span class="p">{</span>
    <span class="kd">static</span> <span class="k">var</span> <span class="nv">key</span> <span class="o">=</span> <span class="s">"userAudioPreferences"</span>
    <span class="k">var</span> <span class="nv">volume</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="c1">// default value</span>
    <span class="k">var</span> <span class="nv">bass</span> <span class="o">=</span> <span class="mf">0.5</span>
    <span class="k">var</span> <span class="nv">treble</span> <span class="o">=</span> <span class="mf">0.5</span>
    <span class="k">var</span> <span class="nv">quality</span> <span class="o">=</span> <span class="mf">1.0</span>
<span class="p">}</span>

<span class="k">var</span> <span class="nv">audioPreferences</span> <span class="o">=</span> <span class="kt">AudioPreferences</span><span class="o">.</span><span class="nf">load</span><span class="p">()</span>

<span class="c1">// user modifies volume</span>
<span class="n">audioPreferences</span><span class="o">.</span><span class="n">volume</span> <span class="o">=</span> <span class="mf">1.0</span>
<span class="n">audioPreferences</span><span class="o">.</span><span class="nf">save</span><span class="p">()</span> <span class="c1">// Audio preferences are saved in user defaults</span>
</code></pre></div></div>
<p>Declaring a type to be <code>UserDefaultsPersistable</code> allows you to easily store it in <code>UserDefaults</code> by only specifying a key. Obviously with this approach you can’t store more than one instance of the same type but when it comes to storing user preferences this is a safety mechanism rather than a limitation.</p>
<p>Feel free to <a href="mailto:orjpap@gmail.com">contact me</a> for tips, feedback, opinions.</p>
<p>Thank you for reading!</p>]]></content><author><name>Orestis Papadopoulos</name></author><category term="Swift" /><category term="UserDefaults" /><category term="iOS" /><category term="Protocols" /><summary type="html"><![CDATA[The user’s defaults database is a key-value store that let’s you persist data across app launches. It is meant to be used to store user preferences. Using the Codeable protocol and a JSONEncoder you can very easily convert Swift types to JSON data in order to store them.]]></summary></entry><entry><title type="html">How To Upload Data To A Server: Multipart/Form-Data HTTP Requests in Swift</title><link href="/swift/http/ios/urlsession/2021/04/26/Multipart-Form-Requests.html" rel="alternate" type="text/html" title="How To Upload Data To A Server: Multipart/Form-Data HTTP Requests in Swift" /><published>2021-04-26T18:33:36+03:00</published><updated>2021-04-26T18:33:36+03:00</updated><id>/swift/http/ios/urlsession/2021/04/26/Multipart-Form-Requests</id><content type="html" xml:base="/swift/http/ios/urlsession/2021/04/26/Multipart-Form-Requests.html"><![CDATA[<p>So you are making your first face beautifier<strong>©</strong> app and it’s about time to upload some images to a server. The backend person asks you to do it via a type of HTTP POST request known as <code>multipart/form-data</code>. Soon you come to realise that <code>URLSession</code> does not provide you with an out of the box <code>URLRequest</code> or <code>DataTask</code> for this specific task, despite the fact that this is a very standard way of uploading data.</p>
<p>And that’s when you reach for <a href="https://github.com/Alamofire/Alamofire">Alamofire</a>.</p>
<p><strong>Or</strong> you can stick with <code>URLSession</code> and make your own <code>MultipartFormDataRequest</code></p>
<p>It works like this:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="nf">uploadImage</span><span class="p">(</span><span class="nv">imageData</span><span class="p">:</span> <span class="kt">Data</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">let</span> <span class="nv">request</span> <span class="o">=</span> <span class="kt">MultipartFormDataRequest</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="s">"https://server.com/uploadPicture"</span><span class="p">)</span><span class="o">!</span><span class="p">)</span>
    <span class="n">request</span><span class="o">.</span><span class="nf">addDataField</span><span class="p">(</span><span class="nv">named</span><span class="p">:</span> <span class="s">"profilePicture"</span><span class="p">,</span> <span class="nv">data</span><span class="p">:</span> <span class="n">imageData</span><span class="p">,</span> <span class="nv">mimeType</span><span class="p">:</span> <span class="s">"img/jpeg"</span><span class="p">)</span>
    <span class="kt">URLSession</span><span class="o">.</span><span class="n">shared</span><span class="o">.</span><span class="nf">dataTask</span><span class="p">(</span><span class="nv">with</span><span class="p">:</span> <span class="n">request</span><span class="p">,</span> <span class="nv">completionHandler</span><span class="p">:</span> <span class="p">{</span>
        <span class="o">...</span>
    <span class="p">})</span><span class="o">.</span><span class="nf">resume</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>
<p><code>MultipartFormDataRequest</code> is very similar to a <code>URLRequest</code> in that it is initialised by a URL. The URL endpoint that you will be sending data to.</p>
<p>Use <code>addTextField</code> to send text and <code>addDataField</code> to send anything that can be converted to <code>Data</code> (images, audio, Grand Theft Auto 2 savefiles, you name it)</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">MultipartFormDataRequest</span> <span class="p">{</span>
    <span class="kd">private</span> <span class="k">let</span> <span class="nv">boundary</span><span class="p">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="kt">UUID</span><span class="p">()</span><span class="o">.</span><span class="n">uuidString</span>
    <span class="kd">private</span> <span class="k">var</span> <span class="nv">httpBody</span> <span class="o">=</span> <span class="kt">NSMutableData</span><span class="p">()</span>
    <span class="k">let</span> <span class="nv">url</span><span class="p">:</span> <span class="kt">URL</span>

    <span class="nf">init</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="kt">URL</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="o">.</span><span class="n">url</span> <span class="o">=</span> <span class="n">url</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="nf">addTextField</span><span class="p">(</span><span class="n">named</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">value</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">httpBody</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="nf">textFormField</span><span class="p">(</span><span class="nv">named</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span> <span class="nv">value</span><span class="p">:</span> <span class="n">value</span><span class="p">))</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kd">func</span> <span class="nf">textFormField</span><span class="p">(</span><span class="n">named</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">value</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">String</span> <span class="p">{</span>
        <span class="k">var</span> <span class="nv">fieldString</span> <span class="o">=</span> <span class="s">"--</span><span class="se">\(</span><span class="n">boundary</span><span class="se">)\r\n</span><span class="s">"</span>
        <span class="n">fieldString</span> <span class="o">+=</span> <span class="s">"Content-Disposition: form-data; name=</span><span class="se">\"\(</span><span class="n">name</span><span class="se">)\"\r\n</span><span class="s">"</span>
        <span class="n">fieldString</span> <span class="o">+=</span> <span class="s">"Content-Type: text/plain; charset=ISO-8859-1</span><span class="se">\r\n</span><span class="s">"</span>
        <span class="n">fieldString</span> <span class="o">+=</span> <span class="s">"Content-Transfer-Encoding: 8bit</span><span class="se">\r\n</span><span class="s">"</span>
        <span class="n">fieldString</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\r\n</span><span class="s">"</span>
        <span class="n">fieldString</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\(</span><span class="n">value</span><span class="se">)\r\n</span><span class="s">"</span>

        <span class="k">return</span> <span class="n">fieldString</span>
    <span class="p">}</span>

    <span class="kd">func</span> <span class="nf">addDataField</span><span class="p">(</span><span class="n">named</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">data</span><span class="p">:</span> <span class="kt">Data</span><span class="p">,</span> <span class="nv">mimeType</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">httpBody</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="nf">dataFormField</span><span class="p">(</span><span class="nv">named</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span> <span class="nv">data</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="nv">mimeType</span><span class="p">:</span> <span class="n">mimeType</span><span class="p">))</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kd">func</span> <span class="nf">dataFormField</span><span class="p">(</span><span class="n">named</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span>
                               <span class="nv">data</span><span class="p">:</span> <span class="kt">Data</span><span class="p">,</span>
                               <span class="nv">mimeType</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Data</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">fieldData</span> <span class="o">=</span> <span class="kt">NSMutableData</span><span class="p">()</span>

        <span class="n">fieldData</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="s">"--</span><span class="se">\(</span><span class="n">boundary</span><span class="se">)\r\n</span><span class="s">"</span><span class="p">)</span>
        <span class="n">fieldData</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="s">"Content-Disposition: form-data; name=</span><span class="se">\"\(</span><span class="n">name</span><span class="se">)\"\r\n</span><span class="s">"</span><span class="p">)</span>
        <span class="n">fieldData</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="s">"Content-Type: </span><span class="se">\(</span><span class="n">mimeType</span><span class="se">)\r\n</span><span class="s">"</span><span class="p">)</span>
        <span class="n">fieldData</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="s">"</span><span class="se">\r\n</span><span class="s">"</span><span class="p">)</span>
        <span class="n">fieldData</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
        <span class="n">fieldData</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="s">"</span><span class="se">\r\n</span><span class="s">"</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">fieldData</span> <span class="k">as</span> <span class="kt">Data</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kd">extension</span> <span class="kt">NSMutableData</span> <span class="p">{</span>
  <span class="kd">func</span> <span class="nf">append</span><span class="p">(</span><span class="n">_</span> <span class="nv">string</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="k">let</span> <span class="nv">data</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="nf">data</span><span class="p">(</span><span class="nv">using</span><span class="p">:</span> <span class="o">.</span><span class="n">utf8</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">self</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>You also need a function to convert a <code>MultipartFormDataRequest</code> to a <code>URLRequest</code> in order to be able to create <code>URLSessionDataTasks</code></p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="nf">asURLRequest</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">URLRequest</span> <span class="p">{</span>
    <span class="k">var</span> <span class="nv">request</span> <span class="o">=</span> <span class="kt">URLRequest</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="n">url</span><span class="p">)</span>

    <span class="n">request</span><span class="o">.</span><span class="n">httpMethod</span> <span class="o">=</span> <span class="s">"POST"</span>
    <span class="n">request</span><span class="o">.</span><span class="nf">setValue</span><span class="p">(</span><span class="s">"multipart/form-data; boundary=</span><span class="se">\(</span><span class="n">boundary</span><span class="se">)</span><span class="s">"</span><span class="p">,</span> <span class="nv">forHTTPHeaderField</span><span class="p">:</span> <span class="s">"Content-Type"</span><span class="p">)</span>

    <span class="n">httpBody</span><span class="o">.</span><span class="nf">appendString</span><span class="p">(</span><span class="s">"--</span><span class="se">\(</span><span class="n">boundary</span><span class="se">)</span><span class="s">--"</span><span class="p">)</span>
    <span class="n">request</span><span class="o">.</span><span class="n">httpBody</span> <span class="o">=</span> <span class="n">httpBody</span> <span class="k">as</span> <span class="kt">Data</span>
    <span class="k">return</span> <span class="n">request</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Bonus round:</p>
<p>A handy <code>URLSession</code> extension. You can also make this an upload task, or use background sessions etc.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">extension</span> <span class="kt">URLSession</span> <span class="p">{</span>
    <span class="kd">func</span> <span class="nf">dataTask</span><span class="p">(</span><span class="n">with</span> <span class="nv">request</span><span class="p">:</span> <span class="kt">MultipartFormDataRequest</span><span class="p">,</span>
                  <span class="nv">completionHandler</span><span class="p">:</span> <span class="kd">@escaping</span> <span class="p">(</span><span class="kt">Data</span><span class="p">?,</span> <span class="kt">URLResponse</span><span class="p">?,</span> <span class="kt">Error</span><span class="p">?)</span> <span class="o">-&gt;</span> <span class="kt">Void</span><span class="p">)</span>
    <span class="o">-&gt;</span> <span class="kt">URLSessionDataTask</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nf">dataTask</span><span class="p">(</span><span class="nv">with</span><span class="p">:</span> <span class="n">request</span><span class="o">.</span><span class="nf">asURLRequest</span><span class="p">(),</span> <span class="nv">completionHandler</span><span class="p">:</span> <span class="n">completionHandler</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And this is it. You can now upload your image to the server. A very good example of how simple (or scary) HTTP can be.</p>
<p>I didn’t go into much detail about the HTTP specifics because:</p>
<ol>
<li>This is a sort of tl;dr blog post where I’m sharing some (I hope) useful code with you</li>
<li>Donny Wals has done an excellent job at explaining this in <a href="https://www.donnywals.com/uploading-images-and-forms-to-a-server-using-urlsession/">his blog post</a></li>
<li>You can read about it <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST">here</a></li>
</ol>
<p>Feel free to <a href="mailto:orjpap@gmail.com">contact me</a> for tips, feedback, opinions.</p>
<p>Thank you for reading!</p>]]></content><author><name>Orestis Papadopoulos</name></author><category term="Swift" /><category term="HTTP" /><category term="iOS" /><category term="URLSession" /><summary type="html"><![CDATA[So you are making your first face beautifier© app and it’s about time to upload some images to a server. The backend person asks you to do it via a type of HTTP POST request known as multipart/form-data. Soon you come to realise that URLSession does not provide you with an out of the box URLRequest or DataTask for this specific task, despite the fact that this is a very standard way of uploading data.]]></summary></entry><entry><title type="html">AVAudioSourceNode, AVAudioSinkNode: Low-Level Audio In Swift</title><link href="/swift/real-time/audio/avfoundation/2020/06/19/avaudiosourcenode.html" rel="alternate" type="text/html" title="AVAudioSourceNode, AVAudioSinkNode: Low-Level Audio In Swift" /><published>2020-06-19T18:33:36+03:00</published><updated>2020-06-19T18:33:36+03:00</updated><id>/swift/real-time/audio/avfoundation/2020/06/19/avaudiosourcenode</id><content type="html" xml:base="/swift/real-time/audio/avfoundation/2020/06/19/avaudiosourcenode.html"><![CDATA[<p>Apple <a href="https://developer.apple.com/videos/play/wwdc2019/510">introduced</a> <strong>AVAudioSourceNode</strong> and <strong>AVAudioSinkNode</strong> in WWDC2019. These two new AVAudio nodes are part of the <a href="https://developer.apple.com/documentation/avfoundation">AVFoundation</a> framework and can be used in macOS 10.15 and iOS 13 onwards.</p>
<p>They provide a way to <strong>process input</strong> from an audio device/file, and <strong>generating output</strong> to a device/file, <em>sample by sample</em>.</p>
<p>AVAudioSourceNode <em>sends</em> audio to an AVAudioEngine node. The audio is computed in a callback and can be rendered in real-time or offline modes.</p>
<p>AVAudioSinkNode <em>receives</em> audio from an AVAudioEngine node. The audio is processed in a callback and can be rendered in real-time or offline modes.</p>
<p>The following code outputs five seconds of white noise using an AVAudioSourceNode:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">AVFoundation</span>

<span class="kd">func</span> <span class="nf">whiteNoise</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">Float</span> <span class="p">{</span>
	<span class="k">return</span> <span class="kt">Float</span><span class="o">.</span><span class="nf">random</span><span class="p">(</span><span class="nv">in</span><span class="p">:</span> <span class="o">-</span><span class="mf">1.0</span><span class="o">...</span><span class="mf">1.0</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">whiteNoiseGenerator</span> <span class="o">=</span> <span class="kt">AVAudioSourceNode</span><span class="p">()</span> <span class="p">{</span> <span class="p">(</span><span class="n">silence</span><span class="p">,</span> <span class="n">timeStamp</span><span class="p">,</span> <span class="n">frameCount</span><span class="p">,</span> <span class="n">audioBufferList</span><span class="p">)</span> <span class="o">-&gt;</span>
    <span class="kt">OSStatus</span> <span class="k">in</span>
    <span class="k">let</span> <span class="nv">ablPointer</span> <span class="o">=</span> <span class="kt">UnsafeMutableAudioBufferListPointer</span><span class="p">(</span><span class="n">audioBufferList</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">frame</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..&lt;</span><span class="kt">Int</span><span class="p">(</span><span class="n">frameCount</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">value</span> <span class="o">=</span> <span class="nf">whiteNoise</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">buffer</span> <span class="k">in</span> <span class="n">ablPointer</span> <span class="p">{</span>
            <span class="k">let</span> <span class="nv">buf</span><span class="p">:</span> <span class="kt">UnsafeMutableBufferPointer</span><span class="o">&lt;</span><span class="kt">Float</span><span class="o">&gt;</span> <span class="o">=</span> <span class="kt">UnsafeMutableBufferPointer</span><span class="p">(</span><span class="n">buffer</span><span class="p">)</span>
            <span class="n">buf</span><span class="p">[</span><span class="n">frame</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">noErr</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">engine</span> <span class="o">=</span> <span class="kt">AVAudioEngine</span><span class="p">()</span>
<span class="n">engine</span><span class="o">.</span><span class="nf">attach</span><span class="p">(</span><span class="n">whiteNoiseGenerator</span><span class="p">)</span>
<span class="n">engine</span><span class="o">.</span><span class="nf">connect</span><span class="p">(</span><span class="n">whiteNoiseGenerator</span><span class="p">,</span> <span class="nv">to</span><span class="p">:</span> <span class="n">engine</span><span class="o">.</span><span class="n">mainMixerNode</span><span class="p">,</span> <span class="nv">format</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>
<span class="n">engine</span><span class="o">.</span><span class="n">mainMixerNode</span><span class="o">.</span><span class="n">outputVolume</span> <span class="o">=</span> <span class="mf">0.5</span>

<span class="k">try!</span> <span class="n">engine</span><span class="o">.</span><span class="nf">start</span><span class="p">()</span>
<span class="nf">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
<span class="n">engine</span><span class="o">.</span><span class="nf">stop</span><span class="p">()</span>
</code></pre></div></div>
<p>Two things might baffle Swift programmers in this example:</p>
<ol>
<li>
<p><strong>UnsafeMutableAudioBufferListPointer</strong> and <strong>UnsafeMutableBufferPointer</strong>.</p>
<p>By default, Swift is memory safe: It prevents direct access to memory and makes sure you’ve initialized everything before you use it. But you can also use <em>unsafe Swift</em>, which lets you access memory directly through pointers. In this example we use an UnsafeMutableBufferPointer instance in low level operations to eliminate uniqueness checks and bounds checks. I recommend reading <a href="https://pfandrade.me/blog/unsafe-swift/">Unsafe Swift</a> by Paulo Andrande to get a better understanding of the unsafe side of Swift.</p>
</li>
<li>
<p>The <strong>OSStatus</strong> return type.</p>
<p>Almost every Apple C API function signals success or failure through their return value, which is of type OSStatus. Any status other than noErr (which is 0) signals an error. You can find more details <a href="https://www.osstatus.com/search/results?platform=all&amp;framework=all&amp;search=">here</a></p>
</li>
</ol>
<h2 id="why-unsafe-swift">Why unsafe Swift?</h2>
<p>First of all unsafe Swift lets you work with <a href="https://codeburst.io/pointers-in-5-minutes-b94f9d1dfdb5">pointers</a> and interoprate with C libraries.</p>
<p>In addition, unsafe Swift can help you gain a performance boost by sacrificing memory safety. The code you write in the AVAudioSourceNode’s block <em>must be realtime compliant</em>. Your callback is called in a real-time thread with a hard deadline. @44,1khz sampling rate with a buffer size of 512 samples gives you ~11ms to complete processing in your callback. If that’s not the case, you get silence. That time limit prohibits:</p>
<ol>
<li>Memory Allocations</li>
<li>Using Locks</li>
<li>Network Requests or any kind of I/O</li>
<li>Memory boundary checks/uniqueness checks</li>
<li>Checking your Twitter</li>
</ol>
<p>Check out <a href="https://github.com/apple/swift/blob/master/docs/OptimizationTips.rst">this guide</a> on writing high-performance Swift code.</p>
<h2 id="conclusion">Conclusion</h2>
<p>AVFoundation really suprised me. It provides a clear, powerful API that can be used to generate audio and I’m looking forward making some stuff with it. I’m wondering how it compares to the Audio Unit impementation performance-wise, or if there’s no difference at all because a core audio implementation is hiding under the hood of the two new AVAudioNodes.</p>
<p>Feel free to <a href="mailto:orjpap@gmail.com">contact me</a> or tweet to me on <a href="https://twitter.com/orjpap">Twitter</a> if you have any additional tips or feedback.</p>
<p>Thanks!</p>]]></content><author><name>Orestis Papadopoulos</name></author><category term="Swift" /><category term="Real-time" /><category term="Audio" /><category term="AVFoundation" /><summary type="html"><![CDATA[Apple introduced AVAudioSourceNode and AVAudioSinkNode in WWDC2019. These two new AVAudio nodes are part of the AVFoundation framework and can be used in macOS 10.15 and iOS 13 onwards.]]></summary></entry><entry><title type="html">Jekyll: Testing Swift Code Blocks</title><link href="/jekyll/swift/testing/2020/05/04/iOS-doctest-jekyll.html" rel="alternate" type="text/html" title="Jekyll: Testing Swift Code Blocks" /><published>2020-05-04T18:33:36+03:00</published><updated>2020-05-04T18:33:36+03:00</updated><id>/jekyll/swift/testing/2020/05/04/iOS-doctest-jekyll</id><content type="html" xml:base="/jekyll/swift/testing/2020/05/04/iOS-doctest-jekyll.html"><![CDATA[<p>Reading through last week's <a href="https://iosdevweekly.com">iOSDevWeekly</a> I came across <a href="https://github.com/SwiftDocOrg/DocTest?utm_campaign=iOS%2BDev%2BWeekly&amp;utm_medium=web&amp;utm_source=iOS%2BDev%2BWeekly%2BIssue%2B454">Doctest</a>, an exciting new project that aims to make Swift documentation <strong>testable</strong>.</p>
<p>The idea is, you can run <code>swift-doctest</code> giving it a bunch of .swift files and then it <strong>evaluates</strong> code blocks in your documentation, returning test results for the given conditions.</p>
<p>It turns out that you can run <code>swift-doctest</code> on <strong>Markdown</strong> files too. What if, we could inject a nice little <code>swift-doctest</code> every time jekyll renders our static website? That way we can <strong>test codeblocks</strong> in blog posts and even get it done <strong>automatically on every build</strong>.</p>
<h2 id="install-doctest">Install DocTest</h2>
<p>Via Homebrew:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>brew <span class="nb">install </span>swiftdocorg/formulae/swift-doctest
</code></pre></div></div>
<p>Or Manually:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git clone https://github.com/SwiftDocOrg/DocTest
<span class="nv">$ </span><span class="nb">cd </span>DocTest
<span class="nv">$ </span>make <span class="nb">install</span>
</code></pre></div></div>
<h2 id="jekyll-hook">Jekyll Hook</h2>
<p><em>note: these are my first 6 lines of Ruby, please be gentle with me</em></p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Put this in a file called swift-doctest.rb on a _plugins folder in your blog root foolder</span>
<span class="no">Jekyll</span><span class="o">::</span><span class="no">Hooks</span><span class="p">.</span><span class="nf">register</span> <span class="ss">:posts</span><span class="p">,</span> <span class="ss">:pre_render</span> <span class="k">do</span> <span class="o">|</span><span class="n">post</span><span class="o">|</span>
	<span class="k">if</span> <span class="n">post</span><span class="p">.</span><span class="nf">data</span><span class="p">[</span><span class="s1">'doctest'</span><span class="p">]</span> <span class="o">==</span> <span class="kp">true</span>
		<span class="n">value</span> <span class="o">=</span> <span class="sx">%x( echo;echo 'swift-doctest for </span><span class="si">#{</span><span class="n">post</span><span class="p">.</span><span class="nf">path</span><span class="si">}</span><span class="sx">';swift-doctest </span><span class="si">#{</span><span class="n">post</span><span class="p">.</span><span class="nf">path</span><span class="si">}</span><span class="sx">; echo;)</span>
		<span class="nb">puts</span> <span class="n">value</span>
	<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>This <a href="https://jekyllrb.com/docs/plugins/hooks/">Jekyl Hook</a> runs every time your site is built, <strong>before</strong> the .md files get rendered to .html files. I put it at this point so that I can do something more sophisticated in the future by probably injecting some html to show me the failed test results.</p>
<p>In order to enable swift-doctest for a post, add <code>doctest: true</code> to the post's front matter.</p>
<h2 id="take-it-for-a-spin">Take it for a spin</h2>
<p>Start a codeblock with <strong>```swift doctest</strong> and then, add an annotation in the format <code>=&gt; (Type) = (Value)</code>, to test the expected type and value of the expression:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">User</span> <span class="p">{</span>
	<span class="k">let</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">user</span> <span class="o">=</span> <span class="kt">User</span><span class="p">(</span><span class="nv">name</span><span class="p">:</span> <span class="s">"Foo"</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">anotherUser</span> <span class="o">=</span> <span class="kt">User</span><span class="p">(</span><span class="nv">name</span><span class="p">:</span> <span class="s">"Bar"</span><span class="p">)</span>
<span class="n">user</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="n">anotherUser</span><span class="o">.</span><span class="n">name</span> <span class="c1">// =&gt; Bool = true</span>
</code></pre></div></div>
<p>Now if you run <code>bundle exec jekyll serve</code> to build and serve your site, the terminal will print a failed test in the <a href="https://testanything.org">TAP format</a></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...

swift-doctest <span class="k">for</span> &lt;path_to_your_blog&gt;/_posts/&lt;blog_post_filename&gt;.md
TAP version 13
1..2
not ok 1 - <span class="sb">`</span>user.name <span class="o">==</span> anotherUser.name<span class="sb">`</span> produces <span class="sb">`</span>Bool <span class="o">=</span> <span class="nb">false</span><span class="sb">`</span>, expected <span class="sb">`</span>Bool <span class="o">=</span> <span class="nb">true</span><span class="sb">`</span>
  <span class="nt">---</span>
  column: 37
  file: &lt;path_to_your_blog&gt;/_posts/&lt;blog_post_filename&gt;.md
  line: 6
  ...
  
...
</code></pre></div></div>
<p>Nice! If you just change the example to:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">User</span> <span class="p">{</span>
	<span class="k">let</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
<span class="p">}</span>

<span class="k">let</span> <span class="nv">user</span> <span class="o">=</span> <span class="kt">User</span><span class="p">(</span><span class="nv">name</span><span class="p">:</span> <span class="s">"Foo"</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">anotherUser</span> <span class="o">=</span> <span class="kt">User</span><span class="p">(</span><span class="nv">name</span><span class="p">:</span> <span class="s">"Bar"</span><span class="p">)</span>
<span class="n">user</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="n">anotherUser</span><span class="o">.</span><span class="n">name</span> <span class="c1">// =&gt; Bool = false</span>
</code></pre></div></div>
<p>And just save the file, you will see:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...

swift-doctest <span class="k">for</span> &lt;path_to_your_blog&gt;/_posts/&lt;blog_post_filename&gt;.md
TAP version 13
1..1
ok 1 - <span class="sb">`</span>user.name <span class="o">==</span> anotherUser.name<span class="sb">`</span> produces <span class="sb">`</span>Bool <span class="o">=</span> <span class="nb">false</span><span class="sb">`</span>
  <span class="nt">---</span>
  column: 36
  file: &lt;path_to_your_blog&gt;/_posts/&lt;blog_post_filename&gt;.md
  line: 6
  ...
  
...

</code></pre></div></div>
<h2 id="conclusion">Conclusion</h2>
<p>That's all you need in order to enable testing for Swift codeblocks in your Jekyll site!</p>
<p>Keep your eyes peeled for further updates to the very promising <a href="https://github.com/SwiftDocOrg/DocTest?utm_campaign=iOS%2BDev%2BWeekly&amp;utm_medium=web&amp;utm_source=iOS%2BDev%2BWeekly%2BIssue%2B454">Doctest</a> since it's still on its early days.</p>
<p>Feel free to <a href="mailto:orjpap@gmail.com">contact me</a> or tweet to me on <a href="https://twitter.com/OrestisPapadop8">Twitter</a> if you have any additional tips or feedback.</p>
<p>Thanks!</p>]]></content><author><name>Orestis Papadopoulos</name></author><category term="Jekyll" /><category term="Swift" /><category term="Testing" /><summary type="html"><![CDATA[Reading through last week's iOSDevWeekly I came across Doctest, an exciting new project that aims to make Swift documentation testable.]]></summary></entry><entry><title type="html">AVAudioSourceNode, AVAudioSinkNode: how I deleted a repo in less than 48hours</title><link href="/swift/real-time/audio/avfoundation/2020/05/04/processAudio.html" rel="alternate" type="text/html" title="AVAudioSourceNode, AVAudioSinkNode: how I deleted a repo in less than 48hours" /><published>2020-05-04T18:33:36+03:00</published><updated>2020-05-04T18:33:36+03:00</updated><id>/swift/real-time/audio/avfoundation/2020/05/04/processAudio</id><content type="html" xml:base="/swift/real-time/audio/avfoundation/2020/05/04/processAudio.html"><![CDATA[<p>Two days ago, I set out to create a simple Swift library for real-time audio processing. I was aiming to provide a boilerplate-free way of <strong>processing input</strong> from an audio device/file, and <strong>generating output</strong> to a device/file, sample by sample (or frame by frame).</p>
<p>Last time I checked there was AudioKit, which is great and you should check it out, but a big dependency to add to a project were you only need to process some audio as well as Core Audio. Apple's lowest level of abstraction audio framework, <strong>Core Audio</strong> (initially released in 2003), which on the front page of its <a href="https://developer.apple.com/documentation/coreaudio">documentation</a> clearly states: &quot;Use the Core Audio framework to interact with device’s audio hardware.&quot;</p>
<p>An audio unit is a software object that performs some sort of work on a stream of audio, frame by frame. Being so close to the hardware comes with a lot of responsibilities, that's why Audio Units take time and code to set up and make sure that everything is OK.</p>
<p>The hello world of audio generators is a sinewave. But let's make some noise instead. In order to do this with Core Audio we need to:</p>
<ol>
<li>Find the default output audio component</li>
<li>Create a new instance of an audio unit and attach it to it</li>
<li>Set the renderBlock property of the audio unit to our noise callback</li>
<li>Start the audio unit</li>
<li>Sleep on the current thread so that we can hear the audio being generated on the real-time thread.</li>
<li>Clean up the audio unit</li>
</ol>
<p>I made a wrapper that provided the following API:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">device</span> <span class="o">=</span> <span class="kt">ProcessAudio</span><span class="o">.</span><span class="n">defaultOutput</span>
<span class="c1">// Make some noise</span>
<span class="n">device</span><span class="o">.</span><span class="n">connect</span> <span class="p">{</span> <span class="n">_</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="n">bufferSize</span> <span class="k">in</span>
    <span class="k">for</span> <span class="n">frameNumber</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..&lt;</span><span class="kt">Int</span><span class="p">(</span><span class="n">bufferSize</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">data</span><span class="p">[</span><span class="n">frameNumber</span><span class="p">]</span> <span class="o">=</span> <span class="kt">Float32</span><span class="o">.</span><span class="nf">random</span><span class="p">(</span><span class="nv">in</span><span class="p">:</span> <span class="mi">0</span><span class="o">..&lt;</span><span class="mi">1</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">})</span>
<span class="n">device</span><span class="o">.</span><span class="nf">start</span><span class="p">()</span>
<span class="nf">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
<span class="n">device</span><span class="o">.</span><span class="nf">stop</span><span class="p">()</span>
</code></pre></div></div>
<p>Turns out AVAudioSourceNode and AVAudioSinkNode <a href="https://developer.apple.com/videos/play/wwdc2019/510">introduced</a> in WWDC2019, can be used in the exact same way.</p>
<h2 id="conclusion">Conclusion</h2>
<p>That's all you need in order to enable testing for Swift codeblocks in your Jekyll site!</p>
<p>Keep your eyes peeled for further updates to the very promising <a href="https://github.com/SwiftDocOrg/DocTest?utm_campaign=iOS%2BDev%2BWeekly&amp;utm_medium=web&amp;utm_source=iOS%2BDev%2BWeekly%2BIssue%2B454">Doctest</a> since it's still on its early days.</p>
<p>Feel free to <a href="mailto:orjpap@gmail.com">contact me</a> or tweet to me on <a href="https://twitter.com/OrestisPapadop8">Twitter</a> if you have any additional tips or feedback.</p>
<p>Thanks!</p>]]></content><author><name>Orestis Papadopoulos</name></author><category term="Swift" /><category term="Real-time" /><category term="Audio" /><category term="AVFoundation" /><summary type="html"><![CDATA[Two days ago, I set out to create a simple Swift library for real-time audio processing. I was aiming to provide a boilerplate-free way of processing input from an audio device/file, and generating output to a device/file, sample by sample (or frame by frame).]]></summary></entry><entry><title type="html">Podfast: a Podcast Discovery App</title><link href="/product/design/swift/ios/2020/05/02/iOS-podfast-edit.html" rel="alternate" type="text/html" title="Podfast: a Podcast Discovery App" /><published>2020-05-02T18:33:36+03:00</published><updated>2020-05-02T18:33:36+03:00</updated><id>/product/design/swift/ios/2020/05/02/iOS-podfast-edit</id><content type="html" xml:base="/product/design/swift/ios/2020/05/02/iOS-podfast-edit.html"><![CDATA[<p>I can clearly recall my mother's disappointment once she realised she couldn’t listen to the radio through her new iPhone. Which made total sense to me.</p>
<p>At the time there was only a built-in app called <a href="https://apps.apple.com/us/app/apple-podcasts/id525463029">Podcasts</a> that allowed you to listen to podcasts. Also, Generation Z's complete lack of interest in the radio experience had already signaled the start of a new era. Podcasting, once an obscure process of transmitting audio content, had now become a distinguished medium for its distribution.</p>
<p>When old media are replaced by new ones, some of their features are dropped ‘cause they no longer serve a purpose. Podfast was inspired by the original process of discovering new radio stations through AM/FM <strong>scanning</strong>, a process so undoubtedly joyous and adventuresome for quite a few people that there's even a hobby invented for indulging in it, called <a href="https://en.wikipedia.org/wiki/DXing">DXing</a>. My idea was that the concept of radio discovery can incorporate so much more user value than just the induction of nostalgic feelings to the users (like, creating a typewriter app does, for example). Since ideas transcend media, its <strong>essence</strong> could be rebottled and repurposed for the Podcast era and even be further expanded.</p>
<p>I thought hard on the radio discovery process and I found that the main characteristics defining it are:</p>
<ol>
<li><strong>Chance:</strong> In case you don’t tune in to your favourite program in time, chance is always involved in the program you will tune in to eventually, also in its elapsed time.</li>
<li><strong>Audio Cues</strong>: instead of visual cues. Even though you can see which frequency corresponds to a specific position of the knob, only the audio provides you with information about whether you are going to like what you hear or not.</li>
<li><strong>Locality</strong>: When you move to another country or region, you will tune in to entirely different stations.</li>
</ol>
<h2 id="implementation">Implementation</h2>
<p>Getting started, at the top level, I described what I was trying to build in the form of a simple <strong>user story</strong>:</p>
<blockquote>
<p>As a listener I want to discover podcasts by scrolling while listening to them</p>
</blockquote>
<p>This was pretty much it. This single user story has since spawned a lot of other stories, tasks, sub-tasks etc. These sub-stories all revolve around the three above-mentioned characteristics. The process was:
(a) think of a scenario
(b) write code that implements it
(c) assess the value it adds for the user
(d) integrate it into the app. That's how I made an iOS app <strong>prototype</strong> pretty quickly, implementing this user story into local podcast audio files and just a <a href="https://developer.apple.com/documentation/uikit/uislider">UISlider</a>.</p>
<video controls width="320" height="576">
  <source src="/assets/images/2019-14-20-podfast.assets/podfast_early_prototype.mp4">
Your browser does not support the video tag.
</video>
<p>My next step was to use some real <strong>data sources</strong>. I turned to <a href="https://rss.itunes.apple.com/en-us">iTunes RSS Feed Generator</a>, a publicly accessible API which returns a <a href="https://rss.itunes.apple.com/api/v1/gr/podcasts/top-podcasts/all/100/explicit.json">JSON file</a> with the Top 100 Podcasts in different regions, regularly updated on an almost weekly basis. After collecting this data I had to jump through some hoops - I won’t bore you with the details - to get the metadata for each podcast (XML RSS feed parsing anyone? 😁) but thankfully, the podcast RSS feed tags are properly standardized in order to get parsed by iTunes, Spotify etc.</p>
<p>At this point, I realised that the less the app's core logic knows about the <strong>specifics</strong> of the various data sources, the better for the app. To achieve this separation, I spent some weeks researching the most common app architecture patterns and ended up re-writing my hacky/scripty view controller logic by using something very similar to <a href="https://www.objc.io/issues/13-architecture/viper/">Viper</a> and <a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html">Uncle Bob's clean architecture</a> but not exactly any of them. For those of you who are interested, you can take a look at the folder called <a href="https://github.com/orjpap/podfast/tree/master/PodFast/Use%20Cases/Discovery">Use Cases</a> and let me know what you think (I’m suspecting I have committed some over-abstraction crimes here). Anyway, my goal behind all this was very clear: I wanted to be able to <strong>switch data sources</strong> on a whim, without having to re-write half of my app. This proved to be very valuable when remote configuration feeding podcast data was added.</p>
<p>I also noticed that podcasts could be organised <strong>by category</strong> and that was pretty neat, since such a minimal visual cue is not prominent enough to distract the user from <strong>listening</strong>. Finally, I replaced the slider with a <a href="https://developer.apple.com/documentation/uikit/uicollectionview">UICollectionView</a> to display the category names and also wrote some simple collision logic:</p>
<video controls width="320" height="576">
  <source src="/assets/images/2019-14-20-podfast.assets/podfast_early_prototype2.mp4">
Your browser does not support the video tag.
</video>
<p>That was the <strong>prototype</strong> I showed to the visual artist/writer Vasia Bakogianni, also known as <a href="https://www.kroutsef.com">@kroutsef</a> and asked her to work as a <strong>graphic designer</strong> for the app. She took it all in and we got straight to work. After a few interesting conversations, brainstorming sessions and design iterations she came up with the <strong>app icon</strong>:</p>
<img src="/assets/images/2019-14-20-podfast.assets/podfast_logo.PNG" alt="podfast_logo" style="zoom:50%;" class ="center"/>
<p>Vasia has not only worked as a designer for the project, but since she is an avid podcast listener, she has also provided valuable feedback on the user experience, as well as hours of interesting app and non-app related conversations. After taking a <strong>short break</strong>, where we had to work on various other projects, we got back to ‘Podfast’ and decided to push towards the app release by setting a strict release date. Since we’d done a lot of groundwork and the concept had already been solidified, we finalized the <strong>designing</strong> aspect of it shortly after:</p>
<p><img src="/assets/images/2019-14-20-podfast.assets/design_screenshot.png" alt="design_screenshot" /></p>
<p>From a software perspective we agreed on a <strong>subset</strong> of features that would be included in the release, a sort of minimum viable product (<strong>MVP</strong>) approach, based on the following principle: before making a significant time and effort investment we have to set out to release the product, deliver it to the users and then channel their input back into the process of development.</p>
<p>Shortly prior to the big release, I realised that since there is <strong>streaming</strong> involved and the loading time experience ranges from “seemingly instant” to &quot;slower than death caused by a natural cause”, we needed a way to indicate the <strong>buffering state</strong>. We decided to go with something different from the established spinner/loader pattern and use <strong>radio static sounds</strong>. The current, simplified implementation has a static sound sample played when <a href="https://developer.apple.com/documentation/avfoundation/avplayer">AVPlayer</a> is <a href="https://github.com/orjpap/podfast/blob/120ef148529dfffed1151919402ca0022014a85d/PodFast/Use%20Cases/Discovery/AudioPlayer.swift#L118-L188">having a rough time</a> buffering. Of course, there is definitely room for improvement by obviously inserting <strong>procedural sound design</strong> into the concept. Spinners are the ultimate playground for graphic designers, so let's also give sound designers the opportunity to indicate <strong>loading states</strong>.</p>
<video controls width="320" height="576">
  <source src="/assets/images/2019-14-20-podfast.assets/streaming_static.mp4">
Your browser does not support the video tag.
</video>
<p>Over a period of one week and a few micro-features later, some of which are:</p>
<ol>
<li>Categories are sorted out by “most listened”</li>
<li>A listen is defined as “1 minute of listening”</li>
<li>Podcast details appear after 30 seconds of listening to a podcast, in order to encourage the listener to pay attention to the audio.</li>
<li>The episode seek time is related to the app's start time.</li>
<li>Curated podcast sources can by dynamically added to the data set. Thanks to <a href="https://firebase.google.com/docs/remote-config">Firebase Remote Configuration</a>,</li>
</ol>
<p>we finally had our <strong>1.0 release</strong>!</p>
<p><img src="/assets/images/podfast_portfolio_halfsize_15.gif" alt="podfast_gif" /></p>
<h2 id="where-to-next">Where to next?</h2>
<p>You can download the app for free from the App Store and give it a try.</p>
<p><a href="https://apps.apple.com/us/app/podfast/id1507685149?ls=1"><img src="/assets/images/download_on_the_app_store.svg" class="appstoreDownload"></a></p>
<p>Our users have already done a great job sharing their feedback with us. We are bound to release an update soon, with improved features that were assimilated thanks to their suggestions. We would also love to hear your own <strong>feedback</strong> on the app <a href="mailto:orjpap@gmail.com">Send us an email</a> or get in touch on Twitter <a href="https://twitter.com/OrestisPapadop8">@orjpap</a>, <a href="https://twitter.com/vasiabakogianni">@kroutsef</a>. Feel free to share with us your favourite podcasts and the category they belong to as well, so we can add them to our collection.</p>
<p>There is still a lot to learn and improve, so further optimization in the departments of <strong>streaming logic</strong>, <strong>sound design</strong> and <strong>visuals</strong> of the app is inevitable. Besides, we’re planning to introduce the parameter of <strong>locality</strong> mentioned above. Instead of just selecting from the US Top 100 and our curated podcasts, the user will be able to discover podcasts that are popular in their respective country.</p>
<p>An <strong>Android app</strong> is also in the making by <a href="https://github.com/Pkoutsokeras">Petros Koutsokeras</a></p>
<p>The <strong>source code</strong> is available for free and can be found on <a href="https://github.com/orjpap/podfast">Github</a>, I'm open to discussions about the implementation/architecture of the app and points that can and should be improved.</p>
<p>To sum up, I will just quote Vasia's carefully crafted words:</p>
<blockquote>
<p>Podfast is, after all, not a digital radio simulation that aspires to send you on a nostalgia trip. It is a tool that re-establishes the user trust in a carefully selected bunch of cultural products picked by the users themselves without strain.</p>
</blockquote>]]></content><author><name>Orestis Papadopoulos</name></author><category term="Product" /><category term="Design" /><category term="Swift" /><category term="iOS" /><summary type="html"><![CDATA[I can clearly recall my mother's disappointment once she realised she couldn’t listen to the radio through her new iPhone. Which made total sense to me.]]></summary></entry></feed>