<?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="https://lalinsky.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://lalinsky.com/" rel="alternate" type="text/html" /><updated>2026-02-19T17:06:15+00:00</updated><id>https://lalinsky.com/feed.xml</id><title type="html">Lukáš Lalinský</title><author><name>Lukáš Lalinský</name><email>lukas@lalinsky.com</email></author><entry><title type="html">Six months of yak shaving a Zig web backend stack</title><link href="https://lalinsky.com/2026/02/19/six-months-of-yak-shaving-a-zig-web-backend-stack.html" rel="alternate" type="text/html" title="Six months of yak shaving a Zig web backend stack" /><published>2026-02-19T00:00:00+00:00</published><updated>2026-02-19T00:00:00+00:00</updated><id>https://lalinsky.com/2026/02/19/six-months-of-yak-shaving-a-zig-web-backend-stack</id><content type="html" xml:base="https://lalinsky.com/2026/02/19/six-months-of-yak-shaving-a-zig-web-backend-stack.html"><![CDATA[<p>A while back I <a href="https://lalinsky.com/2025/10/26/zio-async-io-for-zig.html">wrote about</a> <a href="https://github.com/lalinsky/zio">Zio</a>, my async I/O library
for Zig.
At the end of that post I said the next step was to update my NATS
client and write an HTTP server. Well, one thing led to another,
and I now have a whole web backend stack written entirely in Zig.</p>

<p>It started with NATS. I wanted to cluster my server, NATS seemed like
a good fit, and I thought: how hard would it be to write a Zig client?
Turns out, not that hard. <a href="https://github.com/lalinsky/nats.zig">nats.zig</a> came together well, but it was
using threads and blocking sockets. I felt like I stepped into
the past, I really wanted asynchronous I/O for this.
Every approach I tried (wrapping libuv, wrapping libxev) ended up
requiring constant allocations and reference counting.
It was not nice code. I really wanted Go-style networking APIs.</p>

<p>So I asked myself the stupid question again, how hard could <em>that</em> be?
And that led to a fun, but very long journey.
I’ve already <a href="https://lalinsky.com/2025/10/26/zio-async-io-for-zig.html">written about it</a>.</p>

<p>With Zio working, I needed an HTTP server. I was previously using <a href="https://github.com/karlseguin/http.zig">http.zig</a> by Karl
Seguin, which is a great project, but it runs its own event loop and
I wanted multiple network services sharing the same runtime. So I wrote
<a href="https://github.com/lalinsky/dusty">Dusty</a>, with an API inspired by http.zig but built on Zio. Dusty is
more than just an HTTP server, it’s a full HTTP package. It
includes an easy to use HTTP client with connection pooling, natively
supports WebSocket (both server and client), Server-Sent Events, has
a router with parameter and wildcard support, and a middleware system.
I used llhttp for parsing rather than writing my own, because while
HTTP/1.1 is an easy to read protocol, there are many edge cases and
why not use something that already covers them all.</p>

<p>At this point I had a runtime and an HTTP server, which meant I could
actually build something. I still needed some more client libraries.
The first one was for <a href="https://github.com/lalinsky/memcached.zig">Memcached</a>. That was fairly easy
to build, it uses the same rendezvous hashing algorithm as
the Python client library, I was happy with it.
Then came the <a href="https://github.com/lalinsky/pg.zig">PostgreSQL</a> client.
I adapted <a href="https://github.com/karlseguin/pg.zig">pg.zig</a> to use my own I/O layer,
it was a small change and worked well.
And then I took the Memcached client, removed hashing, replaced the protocol parser,
and turned it into a small <a href="https://github.com/lalinsky/redis.zig">Redis</a> client.
This one is very far from feature-complete, but I don’t use Redis
for much, so it covers just what I needed.</p>

<p>I never expected to be writing networking code in Zig when I started.
But it turns out I now have a stack I actually enjoy working with.
Maybe I need to stop the yak shaving at this point, and finish the
AcoustID project that started it all.</p>

<p>Writing backends in Zig is really not for everything. If you’re building
a CRUD app, Go or Python will get you there faster. But for the
kind of work where performance matters at a low level, like databases,
streaming services, or audio processing, I now consider Zig a good option.
You don’t have to drop down to a different language for the networking
layer.</p>

<p><em>Once Zig 0.16 is released, I’ll probably work on migrating the
libraries to use <code class="language-plaintext highlighter-rouge">std.Io</code>, but there is still some missing
functionality in the APIs that makes it impractical at this point.</em></p>]]></content><author><name>Lukáš Lalinský</name><email>lukas@lalinsky.com</email></author><category term="programming" /><category term="zig" /><category term="networking" /><category term="async" /><summary type="html"><![CDATA[A while back I wrote about Zio, my async I/O library for Zig. At the end of that post I said the next step was to update my NATS client and write an HTTP server. Well, one thing led to another, and I now have a whole web backend stack written entirely in Zig.]]></summary></entry><entry><title type="html">How I turned Zig into my favorite language to write network programs in</title><link href="https://lalinsky.com/2025/10/26/zio-async-io-for-zig.html" rel="alternate" type="text/html" title="How I turned Zig into my favorite language to write network programs in" /><published>2025-10-26T00:00:00+00:00</published><updated>2025-10-26T00:00:00+00:00</updated><id>https://lalinsky.com/2025/10/26/zio-async-io-for-zig</id><content type="html" xml:base="https://lalinsky.com/2025/10/26/zio-async-io-for-zig.html"><![CDATA[<p>I’ve been watching the <a href="https://ziglang.org/">Zig</a> language for a while now, given that it was created for
writing audio software (low-level, no allocations, real time). I never paid too much attention though,
it seemed a little weird to me and I didn’t see the real need. Then I saw a post from <a href="https://github.com/andrewrk">Andrew Kelley</a>
(creator of the language) on Hacker News, about how he reimplemented my Chromaprint algorithm in Zig, and that got me really interested.</p>

<p>I’ve been planning to rewrite AcoustID’s inverted index for a long time, I had a couple of prototypes, but none of the approaches felt right.
I was going through some rough times, wanted to learn something new, so I decided to use the project as an opportunity to learn Zig.
And it was great, writing Zig is a joy. The new version was faster and more scalable than the previous C++ one.
I was happy, until I wanted to add a server interface.</p>

<p>In the previous C++ version, I used <a href="https://www.qt.io/">Qt</a>, which might seem very strange for a server software, but I wanted a
nice way of doing asynchronous I/O and Qt allowed me to do that. It was callback-based, but Qt has a lot of support for
making callbacks usable. In the newer prototypes, I used Go, specifically for the ease of networking and concurrency.
With Zig, I was stuck. There are some Zig HTTP servers, so I could use those. I wanted to implement my legacy TCP server as well,
and that’s a lot harder, unless I want to spawn a lot of threads. Then I made a crazy decision, to use Zig also for implementing
a clustered layer on top of my server, using NATS as a messaging system, so I wrote a <a href="https://github.com/lalinsky/nats.zig">Zig NATS client</a>,
and that gave me a lot of experience with Zig’s networking capabilities.</p>

<p>Fast forward to today, I’m happy to introduce <a href="https://github.com/lalinsky/zio">Zio, an asynchronous I/O and concurrency library for Zig</a>.
If you look at the examples, you will not really see where is the asynchronous I/O, but it’s there, in the background and that’s
the point. Writing asynchronous code with callbacks is a pain. Not only that, it requires a lot of allocations, because you need
state to survive across callbacks. Zio is an implementation of Go style concurrency, but limited to what’s possible in Zig.
Zio tasks are stackful coroutines with fixed-size stacks. When you run <code class="language-plaintext highlighter-rouge">stream.read()</code>, this will initiate the I/O operation in the background
and then suspend the current task until the I/O operation is done. When it’s done, the task will be resumed, and the result will be returned.
That gives you the illusion of synchronous code, allowing for much simpler state management.</p>

<p>Zio support fully asynchronous network and file I/O, has synchronization primitives (mutexes, condition variables, etc.) that work with the cooperative runtime,
has Go-style channels, OS signal watches and more. Tasks can run in single-threaded mode, or multi-threaded, in which case they can migrate from thread to thread
for lower latency and better load balancing.</p>

<p>And it’s FAST. I don’t want to be posting benchmarks here, maybe later when I have more complex ones, but the single-threaded mode is beating any framework I’ve tried so far.
It’s much faster than both Go and Rust’s Tokio. Context switching is virtually free, comparable to a function call. The multi-threaded mode,
while still not being as robust as Go/Tokio, has comparable performance. It’s still a bit faster than either of them, but that performance
might go down as I add more fairness features.</p>

<p>Because it implements the standard interfaces for reader/writer, you can actually use external libraries that are unaware they are running within Zio. Here is an example of a HTTP server:</p>

<div class="language-zig highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="n">std</span> <span class="o">=</span> <span class="nb">@import</span><span class="p">(</span><span class="s">"std"</span><span class="p">);</span>
<span class="k">const</span> <span class="n">zio</span> <span class="o">=</span> <span class="nb">@import</span><span class="p">(</span><span class="s">"zio"</span><span class="p">);</span>

<span class="k">const</span> <span class="n">MAX_REQUEST_HEADER_SIZE</span> <span class="o">=</span> <span class="mi">64</span> <span class="o">*</span> <span class="mi">1024</span><span class="p">;</span>

<span class="k">fn</span> <span class="n">connectionTask</span><span class="p">(</span><span class="n">rt</span><span class="p">:</span> <span class="o">*</span><span class="n">zio</span><span class="p">.</span><span class="py">Runtime</span><span class="p">,</span> <span class="n">stream</span><span class="p">:</span> <span class="n">zio</span><span class="p">.</span><span class="py">net</span><span class="p">.</span><span class="py">Stream</span><span class="p">)</span> <span class="o">!</span><span class="k">void</span> <span class="p">{</span>
    <span class="k">defer</span> <span class="n">stream</span><span class="p">.</span><span class="nf">close</span><span class="p">(</span><span class="n">rt</span><span class="p">);</span>

    <span class="k">var</span> <span class="n">read_buffer</span><span class="p">:</span> <span class="p">[</span><span class="n">MAX_REQUEST_HEADER_SIZE</span><span class="p">]</span><span class="kt">u8</span> <span class="o">=</span> <span class="k">undefined</span><span class="p">;</span>
    <span class="k">var</span> <span class="n">reader</span> <span class="o">=</span> <span class="n">stream</span><span class="p">.</span><span class="nf">reader</span><span class="p">(</span><span class="n">rt</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">read_buffer</span><span class="p">);</span>

    <span class="k">var</span> <span class="n">write_buffer</span><span class="p">:</span> <span class="p">[</span><span class="mi">4096</span><span class="p">]</span><span class="kt">u8</span> <span class="o">=</span> <span class="k">undefined</span><span class="p">;</span>
    <span class="k">var</span> <span class="n">writer</span> <span class="o">=</span> <span class="n">stream</span><span class="p">.</span><span class="nf">writer</span><span class="p">(</span><span class="n">rt</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">write_buffer</span><span class="p">);</span>

    <span class="k">var</span> <span class="n">server</span> <span class="o">=</span> <span class="n">std</span><span class="p">.</span><span class="py">http</span><span class="p">.</span><span class="py">Server</span><span class="p">.</span><span class="nf">init</span><span class="p">(</span>
        <span class="o">&amp;</span><span class="n">reader</span><span class="p">.</span><span class="py">interface</span><span class="p">,</span>
        <span class="o">&amp;</span><span class="n">writer</span><span class="p">.</span><span class="py">interface</span><span class="p">,</span>
    <span class="p">);</span>

    <span class="k">while</span> <span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">var</span> <span class="n">request</span> <span class="o">=</span> <span class="k">try</span> <span class="n">server</span><span class="p">.</span><span class="nf">receiveHead</span><span class="p">();</span>
        <span class="k">try</span> <span class="n">request</span><span class="p">.</span><span class="nf">respond</span><span class="p">(</span><span class="s">"hello"</span><span class="p">,</span> <span class="o">.</span><span class="p">{</span> <span class="p">.</span><span class="py">status</span> <span class="o">=</span> <span class="p">.</span><span class="py">ok</span> <span class="p">});</span>

        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">request</span><span class="p">.</span><span class="py">head</span><span class="p">.</span><span class="py">keep_alive</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="n">serverTask</span><span class="p">(</span><span class="n">rt</span><span class="p">:</span> <span class="o">*</span><span class="n">zio</span><span class="p">.</span><span class="py">Runtime</span><span class="p">)</span> <span class="o">!</span><span class="k">void</span> <span class="p">{</span>
    <span class="k">const</span> <span class="n">addr</span> <span class="o">=</span> <span class="k">try</span> <span class="n">zio</span><span class="p">.</span><span class="py">net</span><span class="p">.</span><span class="py">IpAddress</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="s">"127.0.0.1"</span><span class="p">,</span> <span class="mi">8080</span><span class="p">);</span>

    <span class="k">const</span> <span class="n">server</span> <span class="o">=</span> <span class="k">try</span> <span class="n">addr</span><span class="p">.</span><span class="nf">listen</span><span class="p">(</span><span class="n">rt</span><span class="p">,</span> <span class="o">.</span><span class="p">{});</span>
    <span class="k">defer</span> <span class="n">server</span><span class="p">.</span><span class="nf">close</span><span class="p">(</span><span class="n">rt</span><span class="p">);</span>

    <span class="k">while</span> <span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">const</span> <span class="n">stream</span> <span class="o">=</span> <span class="k">try</span> <span class="n">server</span><span class="p">.</span><span class="nf">accept</span><span class="p">(</span><span class="n">rt</span><span class="p">);</span>
        <span class="k">errdefer</span> <span class="n">stream</span><span class="p">.</span><span class="nf">close</span><span class="p">(</span><span class="n">rt</span><span class="p">);</span>

        <span class="k">var</span> <span class="n">task</span> <span class="o">=</span> <span class="k">try</span> <span class="n">rt</span><span class="p">.</span><span class="nf">spawn</span><span class="p">(</span>
            <span class="n">connectionTask</span><span class="p">,</span> <span class="o">.</span><span class="p">{</span> <span class="n">rt</span><span class="p">,</span> <span class="n">stream</span> <span class="p">},</span> <span class="o">.</span><span class="p">{}</span>
        <span class="p">);</span>
        <span class="n">task</span><span class="p">.</span><span class="nf">deinit</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">pub</span> <span class="k">fn</span> <span class="n">main</span><span class="p">()</span> <span class="o">!</span><span class="k">void</span> <span class="p">{</span>
    <span class="k">var</span> <span class="n">gpa</span> <span class="o">=</span> <span class="n">std</span><span class="p">.</span><span class="py">heap</span><span class="p">.</span><span class="nf">GeneralPurposeAllocator</span><span class="p">(</span><span class="o">.</span><span class="p">{}){};</span>
    <span class="k">defer</span> <span class="mi">_</span> <span class="o">=</span> <span class="n">gpa</span><span class="p">.</span><span class="nf">deinit</span><span class="p">();</span>
    <span class="k">const</span> <span class="n">allocator</span> <span class="o">=</span> <span class="n">gpa</span><span class="p">.</span><span class="nf">allocator</span><span class="p">();</span>

    <span class="k">var</span> <span class="n">runtime</span> <span class="o">=</span> <span class="k">try</span> <span class="n">zio</span><span class="p">.</span><span class="py">Runtime</span><span class="p">.</span><span class="nf">init</span><span class="p">(</span><span class="n">allocator</span><span class="p">,</span> <span class="o">.</span><span class="p">{});</span>
    <span class="k">defer</span> <span class="n">runtime</span><span class="p">.</span><span class="nf">deinit</span><span class="p">();</span>

    <span class="k">try</span> <span class="n">runtime</span><span class="p">.</span><span class="nf">runUntilComplete</span><span class="p">(</span><span class="n">serverTask</span><span class="p">,</span> <span class="o">.</span><span class="p">{</span><span class="o">&amp;</span><span class="n">runtime</span><span class="p">},</span> <span class="o">.</span><span class="p">{});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>When I started working with Zig, I really thought it’s going to be a niche language to write the fast code in, and then I’ll need a layer on top of
that in a different language. With Zio, that changed. The next step for me is to update my NATS client to use Zio internally. And after that,
I’m going to work on a HTTP client/server library based on Zio.</p>]]></content><author><name>Lukáš Lalinský</name><email>lukas@lalinsky.com</email></author><category term="programming" /><category term="zig" /><category term="networking" /><category term="async" /><summary type="html"><![CDATA[I’ve been watching the Zig language for a while now, given that it was created for writing audio software (low-level, no allocations, real time). I never paid too much attention though, it seemed a little weird to me and I didn’t see the real need. Then I saw a post from Andrew Kelley (creator of the language) on Hacker News, about how he reimplemented my Chromaprint algorithm in Zig, and that got me really interested.]]></summary></entry><entry><title type="html">Goodbye, Google Chrome</title><link href="https://lalinsky.com/2025/03/12/goodbye-google-chrome.html" rel="alternate" type="text/html" title="Goodbye, Google Chrome" /><published>2025-03-12T00:00:00+00:00</published><updated>2025-03-12T00:00:00+00:00</updated><id>https://lalinsky.com/2025/03/12/goodbye-google-chrome</id><content type="html" xml:base="https://lalinsky.com/2025/03/12/goodbye-google-chrome.html"><![CDATA[<p>I’ve upgraded my laptop today, that included Google Chrome, and surprise, surprise, when it restarted, it started telling me that the uBlock Origin extension is no longer supported and will be disabled. I’m paying for YouTube Premium, but I still can’t live without ad blocker. It turns out you can just enable the extension again and it will keep working, but for how long. So I decide to switch. I’ve been using Chrome from the very early times, long before it was mainstream. The more popular Chrome was, the more hostile Google was. Now removing my ad blocker, that’s just saying they don’t want me to use their browser. That’s OK, now we have alternatives, even with ad blockers built in. My first choice would have been Opera, but unfortunately 1Password doesn’t support it, so I went to the next best option, Brave. So far, I’m pretty happy with it.</p>]]></content><author><name>Lukáš Lalinský</name><email>lukas@lalinsky.com</email></author><category term="misc" /><category term="rant" /><summary type="html"><![CDATA[I’ve upgraded my laptop today, that included Google Chrome, and surprise, surprise, when it restarted, it started telling me that the uBlock Origin extension is no longer supported and will be disabled. I’m paying for YouTube Premium, but I still can’t live without ad blocker. It turns out you can just enable the extension again and it will keep working, but for how long. So I decide to switch. I’ve been using Chrome from the very early times, long before it was mainstream. The more popular Chrome was, the more hostile Google was. Now removing my ad blocker, that’s just saying they don’t want me to use their browser. That’s OK, now we have alternatives, even with ad blockers built in. My first choice would have been Opera, but unfortunately 1Password doesn’t support it, so I went to the next best option, Brave. So far, I’m pretty happy with it.]]></summary></entry><entry><title type="html">My AI helpers, CodeRabbit and SourceGraph Cody</title><link href="https://lalinsky.com/2025/03/12/my-ai-helpers-coderabbit-and-sourcegraph-cody.html" rel="alternate" type="text/html" title="My AI helpers, CodeRabbit and SourceGraph Cody" /><published>2025-03-12T00:00:00+00:00</published><updated>2025-03-12T00:00:00+00:00</updated><id>https://lalinsky.com/2025/03/12/my-ai-helpers-coderabbit-and-sourcegraph-cody</id><content type="html" xml:base="https://lalinsky.com/2025/03/12/my-ai-helpers-coderabbit-and-sourcegraph-cody.html"><![CDATA[<p>I’ve been an early adopter of AI coding tools. I’ve been using GitHub Copilot from the technical preview stages in 2021. It was mind-blowing to me. The interface was pretty minimal compared to what we have now, but even at the stage, it was revolutionizing the way I work. I’ve dreamed for a long time about programming without having to actually write all the code, and it was starting to become a reality. All in all, I was pretty happy with it.</p>

<p>Last year, I discovered <a href="https://sourcegraph.com/cody">Cody</a> from <a href="https://sourcegraph.com/">SourceGraph</a>. I’ve tried the trial and I was hooked. It had so much more context about the code I’m working on. I could just select a function, tell it to refactor something on it, and it would do it directly in my editor. Writing documentation, generating tests, writing new code, everything become easier. I’ve used it last year to write a replacement of the <a href="https://github.com/acoustid/acoustid-index">acoustid-index</a> server, something I’ve been planning for a long time, but I decided to also learn a new language, <a href="https://ziglang.org/">Zig</a>, on the project. Cody made the process really effortless. It included countless refactoring, as I was still learning the right patterns in the language, and I was doing most of the work without actually writing the code myself. This year, I’ve started using the chat with thinking models a lot more often, and Cody’s ability to apply the code blocks from the chat to the editor. Even better, I’m actually using this for free, as part of their support for open source. It’s such a good tool that I’d be happy to pay for now, and will definitely start doing that once my current free license expires.</p>

<p>And this year I discovered <a href="https://www.coderabbit.ai/">CodeRabbit</a> for automated code reviews. I was super skeptical about this, but they also have a free plan for open source projects, do I decided to give it a try. I’m maintaining AcoustID alone, so having another set of eyes looking at the code, even if mechanical ones, is welcome. And I was blown away. On the first pull request, it actually found a small logical error I had in the code. And this kept happening again and again. After some time, I switched it to the assertive profile, and now I actually enjoy opening a pull request and going through the suggestions it makes. Yes, sometimes they are obsessive, but that’s OK. I’ve tried alternatives, like Gemini or Copilot, both having options to do code reviews, but the level of quality is somewhere completely elsewhere. Gemini and Copilot feel like useless toys compared to CodeRabbit.</p>

<p>The last four years have completely changed my approach to programming, and for the better. As good as all these new AI tools are, I don’t really expect them to be replacing technical programming jobs. You really need to evaluate their outputs, and if you are not able to do that critically, you will deal with a lot of bullshit code. But if you can judge the quality of the output, these are great helpers and I’m really looking forward to what the future brings.</p>]]></content><author><name>Lukáš Lalinský</name><email>lukas@lalinsky.com</email></author><category term="tools" /><category term="programming" /><category term="ai" /><summary type="html"><![CDATA[I’ve been an early adopter of AI coding tools. I’ve been using GitHub Copilot from the technical preview stages in 2021. It was mind-blowing to me. The interface was pretty minimal compared to what we have now, but even at the stage, it was revolutionizing the way I work. I’ve dreamed for a long time about programming without having to actually write all the code, and it was starting to become a reality. All in all, I was pretty happy with it.]]></summary></entry><entry><title type="html">Msgpack serialization library for Zig</title><link href="https://lalinsky.com/2024/11/30/msgpack-zig.html" rel="alternate" type="text/html" title="Msgpack serialization library for Zig" /><published>2024-11-30T00:00:00+00:00</published><updated>2024-11-30T00:00:00+00:00</updated><id>https://lalinsky.com/2024/11/30/msgpack-zig</id><content type="html" xml:base="https://lalinsky.com/2024/11/30/msgpack-zig.html"><![CDATA[<p>I’ve been playing with Zig over the last few weeks. The language had been on my radar for a long time, since it was originally developed for writing audio software,
but I never paid too much attention to it. It seems that it’s becoming more popular, so I’ve decided to learn it and
picked a small task of rewriting the AcoustID fingerprint index server in it. That is still in progress, but there is one side product that is almost
ready, a <a href="https://github.com/lalinsky/msgpack.zig">library for handling msgpack serialization</a>.</p>

<p>The library can be only used with static schemas, defined using Zig’s type system. There are many options for generating compact messages, almost competing with protobuf,
but without separate proto files and protoc. I’m quite happy with the API. It’s mainly possible due to Zig’s comptime type reflection.</p>

<p>This is the most basic usage:</p>

<div class="language-zig highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="n">std</span> <span class="o">=</span> <span class="nb">@import</span><span class="p">(</span><span class="s">"std"</span><span class="p">);</span>
<span class="k">const</span> <span class="n">msgpack</span> <span class="o">=</span> <span class="nb">@import</span><span class="p">(</span><span class="s">"msgpack"</span><span class="p">);</span>

<span class="k">const</span> <span class="n">Message</span> <span class="o">=</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">name</span><span class="p">:</span> <span class="p">[]</span><span class="k">const</span> <span class="kt">u8</span><span class="p">,</span>
    <span class="n">age</span><span class="p">:</span> <span class="kt">u8</span><span class="p">,</span>
<span class="p">};</span>

<span class="k">var</span> <span class="n">buffer</span> <span class="o">=</span> <span class="n">std</span><span class="p">.</span><span class="nf">ArrayList</span><span class="p">(</span><span class="kt">u8</span><span class="p">).</span><span class="nf">init</span><span class="p">(</span><span class="n">allocator</span><span class="p">);</span>
<span class="k">defer</span> <span class="n">buffer</span><span class="p">.</span><span class="nf">deinit</span><span class="p">();</span>

<span class="k">try</span> <span class="n">msgpack</span><span class="p">.</span><span class="nf">encode</span><span class="p">(</span><span class="n">Message</span><span class="p">{</span>
    <span class="p">.</span><span class="py">name</span> <span class="o">=</span> <span class="s">"John"</span><span class="p">,</span>
    <span class="p">.</span><span class="py">age</span> <span class="o">=</span> <span class="mi">20</span><span class="p">,</span>
<span class="p">},</span> <span class="n">buffer</span><span class="p">.</span><span class="nf">writer</span><span class="p">());</span>

<span class="k">const</span> <span class="n">decoded</span> <span class="o">=</span> <span class="k">try</span> <span class="n">msgpack</span><span class="p">.</span><span class="nf">decodeFromSlice</span><span class="p">(</span><span class="n">Message</span><span class="p">,</span> <span class="n">allocator</span><span class="p">,</span> <span class="n">buffer</span><span class="p">.</span><span class="py">items</span><span class="p">);</span>
<span class="k">defer</span> <span class="n">decoded</span><span class="p">.</span><span class="nf">deinit</span><span class="p">();</span>

<span class="n">std</span><span class="p">.</span><span class="py">debug</span><span class="p">.</span><span class="nf">assert</span><span class="p">(</span><span class="n">std</span><span class="p">.</span><span class="py">mem</span><span class="p">.</span><span class="nf">eql</span><span class="p">(</span><span class="kt">u8</span><span class="p">,</span> <span class="n">decoded</span><span class="p">.</span><span class="py">name</span><span class="p">,</span> <span class="s">"John"</span><span class="p">));</span>
<span class="n">std</span><span class="p">.</span><span class="py">debug</span><span class="p">.</span><span class="nf">assert</span><span class="p">(</span><span class="n">decoded</span><span class="p">.</span><span class="py">age</span> <span class="o">==</span> <span class="mi">20</span><span class="p">);</span>
</code></pre></div></div>

<p>See the project on <a href="https://github.com/lalinsky/msgpack.zig">GitHub</a> for more details.</p>]]></content><author><name>Lukáš Lalinský</name><email>lukas@lalinsky.com</email></author><category term="programming" /><category term="programming" /><category term="zig" /><category term="msgpack" /><summary type="html"><![CDATA[I’ve been playing with Zig over the last few weeks. The language had been on my radar for a long time, since it was originally developed for writing audio software, but I never paid too much attention to it. It seems that it’s becoming more popular, so I’ve decided to learn it and picked a small task of rewriting the AcoustID fingerprint index server in it. That is still in progress, but there is one side product that is almost ready, a library for handling msgpack serialization.]]></summary></entry><entry><title type="html">Chromaprint 1.4 released</title><link href="https://lalinsky.com/2016/12/03/chromaprint-1-4-released.html" rel="alternate" type="text/html" title="Chromaprint 1.4 released" /><published>2016-12-03T00:00:00+00:00</published><updated>2016-12-03T00:00:00+00:00</updated><id>https://lalinsky.com/2016/12/03/chromaprint-1-4-released</id><content type="html" xml:base="https://lalinsky.com/2016/12/03/chromaprint-1-4-released.html"><![CDATA[<p>A new version of Chromaprint has been released. This is a fairly big release I originally intended to call 2.0,
but one key feature I was planning to include is not yet finished, so I decided to go with 1.4 instead.</p>

<p>So what’s new?</p>

<p>The biggest feature is that all components of audio fingerprinting process now work in a streaming fashion and
can provide partial results at any time. That means that it’s now possible to feed a continuous audio stream
to the process and get back partial fingerprints. This is useful if you want to fingerprint e.g. an internet radio stream
and do not want to explicitly split the stream into small chunks. There are also side effects of these changes and
the whole process is now faster and uses less memory.</p>

<p>This change is also reflected in the fpcalc utility, which can now work on streams.
In fact, the fpcalc utility has been completely rewritten. It now also supports JSON output for easier integration,
since you can find JSON parser in the standard library of almost every new programing language.</p>

<p>Here is an example using an online radio:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ fpcalc -ts -chunk 10 -overlap -json http://icecast2.play.cz/radio1.mp3
{"timestamp": 1480789416.14, "duration": 12.60, "fingerprint": "AQAAUFSSTEnCRBKeZsR0..."}
{"timestamp": 1480789423.68, "duration": 12.60, "fingerprint": "AQAAUZOSRIsUTkGz9SCZ..."}
{"timestamp": 1480789433.68, "duration": 12.60, "fingerprint": "AQAAUYmWfJIoiNIRHzsl..."}
</code></pre></div></div>

<p>Or you can fingerprint raw pcm data from an external audio input:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ arecord --format=S16 --rate=44100 --channels=1 --file-type=raw \
    | fpcalc -format s16le -rate 44100 -channels 1 -ts -chunk 10 -overlap -json -
{"timestamp": 1480789965.67, "duration": 12.60, "fingerprint": "AQAAUFqkMVmyJMHWBa97..."}
{"timestamp": 1480789975.81, "duration": 12.60, "fingerprint": "AQAAUVGYSEkXJvit4ce1..."}
{"timestamp": 1480789985.72, "duration": 12.60, "fingerprint": "AQAAUcoSpRunwN6Op_hy..."}
</code></pre></div></div>

<p>This opens up many options how Chromaprint can be used outside of AcoustID.</p>

<p>There has also been a big source code cleanup. A lot of old code has been removed. We started using C++11 features,
so it’s no longer possible to compile Chromaprintwith old C++ compilers. Unit tests no longer depend on boost.
KissFFT is now bundled in the package and used as a fallback if no other FFT library is found. That means Chromaprint can be now
build without any external dependencies.</p>

<p>The public C API now uses standard fixed-size int types from stdint.h. This breaks API-level backwards compatibility,
you will need to modify your programs. The binary interface has not changed and programs compiled against the old version of
the library will continue working.</p>

<p>All source code from Chromaprint written by me has been relicensed from LGPL to MIT. Note that this does not mean much for the
library as a whole, since it still depends on LGPL code, but it’s now easier to reuse parts of the code in other projects, if needed.</p>

<p>We also have fpcalc binaries for ARM processors now. They were built and tested on Raspberry Pi, but might work on other ARM devices.</p>

<p>Download:</p>

<ul>
  <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-1.4.tar.gz">Source code tarball</a> (597 KB)</li>
  <li>Static binaries for the <code class="language-plaintext highlighter-rouge">fpcalc</code> tool
    <ul>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.4-windows-i686.zip">Windows, i686</a> (1.4 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.4-windows-x86_64.zip">Windows, x86_64</a> (1.5 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.4-macos-i386.tar.gz">macOS, i386</a> (1.1 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.4-macos-x86_64.tar.gz">macOS, x86_64</a> (1.2 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.4-linux-i686.tar.gz">Linux, i686</a> (1.3 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.4-linux-x86_64.tar.gz">Linux, x86_64</a> (1.2 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.4-linux-armhf.tar.gz">Linux, armhf</a> (1.2 MB)</li>
    </ul>
  </li>
</ul>]]></content><author><name>Lukáš Lalinský</name><email>lukas@lalinsky.com</email></author><category term="acoustid" /><category term="acoustid" /><category term="chromaprint" /><category term="release" /><summary type="html"><![CDATA[A new version of Chromaprint has been released. This is a fairly big release I originally intended to call 2.0, but one key feature I was planning to include is not yet finished, so I decided to go with 1.4 instead.]]></summary></entry><entry><title type="html">mbdata 2016.07.17 released</title><link href="https://lalinsky.com/2016/07/17/mbdata-2016-07-17-released.html" rel="alternate" type="text/html" title="mbdata 2016.07.17 released" /><published>2016-07-17T00:00:00+00:00</published><updated>2016-07-17T00:00:00+00:00</updated><id>https://lalinsky.com/2016/07/17/mbdata-2016-07-17-released</id><content type="html" xml:base="https://lalinsky.com/2016/07/17/mbdata-2016-07-17-released.html"><![CDATA[<p>I have released a new version of <a href="https://pypi.python.org/pypi/mbdata">mbdata</a>.
It’s a small Python package for working with the MusicBrainz database using SQLAlchemy.</p>

<p>This version updates the SQLAlchemy models to the latest MusicBrainz database schema.
It also adds support for Python 3 in addition to Python 2.</p>

<p>Install:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip install mbdata==2016.7.17
</code></pre></div></div>]]></content><author><name>Lukáš Lalinský</name><email>lukas@lalinsky.com</email></author><category term="musicbrainz" /><category term="musicbrainz" /><category term="mbdata" /><category term="python" /><category term="release" /><summary type="html"><![CDATA[I have released a new version of mbdata. It’s a small Python package for working with the MusicBrainz database using SQLAlchemy.]]></summary></entry><entry><title type="html">Chromaprint 1.3.2 released</title><link href="https://lalinsky.com/2016/07/09/chromaprint-1-3-2-released.html" rel="alternate" type="text/html" title="Chromaprint 1.3.2 released" /><published>2016-07-09T00:00:00+00:00</published><updated>2016-07-09T00:00:00+00:00</updated><id>https://lalinsky.com/2016/07/09/chromaprint-1-3-2-released</id><content type="html" xml:base="https://lalinsky.com/2016/07/09/chromaprint-1-3-2-released.html"><![CDATA[<p>A new version of Chromaprint has been released.
This is a very small bug fix release fixing fpcalc crash on a corrupt file.</p>

<p>Changes since version 1.3.1:</p>

<ul>
  <li>Fixed crash on an invalid audio file that FFmpeg could not decode.</li>
  <li>Fixed build on Ubuntu 14.04 with libav.</li>
</ul>

<p>Download:</p>

<ul>
  <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-1.3.2.tar.gz">Source code tarball</a> (525 KB)</li>
  <li>Static binaries for the <code class="language-plaintext highlighter-rouge">fpcalc</code> tool
    <ul>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3.2-win-i686.zip">Windows, 32-bit</a> (1 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3.2-win-x86_64.zip">Windows, 64-bit</a> (1 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3.2-osx-i386.tar.gz">Mac OS X, 32-bit, 10.4+</a> (964 KB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3.2-osx-x86_64.tar.gz">Mac OS X, 64-bit, 10.4+</a> (944 KB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3.2-linux-i686.tar.gz">Linux, 32-bit</a> (1 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3.2-linux-x86_64.tar.gz">Linux, 64-bit</a> (1 MB)</li>
    </ul>
  </li>
</ul>]]></content><author><name>Lukáš Lalinský</name><email>lukas@lalinsky.com</email></author><category term="acoustid" /><category term="acoustid" /><category term="chromaprint" /><category term="release" /><summary type="html"><![CDATA[A new version of Chromaprint has been released. This is a very small bug fix release fixing fpcalc crash on a corrupt file.]]></summary></entry><entry><title type="html">Chromaprint 1.3.1 released</title><link href="https://lalinsky.com/2016/02/10/chromaprint-1-3-1-released.html" rel="alternate" type="text/html" title="Chromaprint 1.3.1 released" /><published>2016-02-10T00:00:00+00:00</published><updated>2016-02-10T00:00:00+00:00</updated><id>https://lalinsky.com/2016/02/10/chromaprint-1-3-1-released</id><content type="html" xml:base="https://lalinsky.com/2016/02/10/chromaprint-1-3-1-released.html"><![CDATA[<p>A new version of Chromaprint has been released.</p>

<p>Changes since version 1.3:</p>

<ul>
  <li>Fixed <code class="language-plaintext highlighter-rouge">fpcalc -length</code> to actually restrict fingerprints the requested length.</li>
  <li>Fixed SONAME version for the shared library.</li>
</ul>

<p>Download:</p>

<ul>
  <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-1.3.1.tar.gz">Source code tarball</a> (525 KB)</li>
  <li>Static binaries for the <code class="language-plaintext highlighter-rouge">fpcalc</code> tool
    <ul>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3.1-win-i686.zip">Windows, 32-bit</a> (1 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3.1-win-x86_64.zip">Windows, 64-bit</a> (1 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3.1-osx-i386.tar.gz">Mac OS X, 32-bit, 10.4+</a> (964 KB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3.1-osx-x86_64.tar.gz">Mac OS X, 64-bit, 10.4+</a> (944 KB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3.1-linux-i686.tar.gz">Linux, 32-bit</a> (1 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3.1-linux-x86_64.tar.gz">Linux, 64-bit</a> (1 MB)</li>
    </ul>
  </li>
</ul>]]></content><author><name>Lukáš Lalinský</name><email>lukas@lalinsky.com</email></author><category term="acoustid" /><category term="acoustid" /><category term="chromaprint" /><category term="release" /><summary type="html"><![CDATA[A new version of Chromaprint has been released.]]></summary></entry><entry><title type="html">Chromaprint 1.3 released</title><link href="https://lalinsky.com/2016/02/03/chromaprint-1-3-released.html" rel="alternate" type="text/html" title="Chromaprint 1.3 released" /><published>2016-02-03T00:00:00+00:00</published><updated>2016-02-03T00:00:00+00:00</updated><id>https://lalinsky.com/2016/02/03/chromaprint-1-3-released</id><content type="html" xml:base="https://lalinsky.com/2016/02/03/chromaprint-1-3-released.html"><![CDATA[<p>A new version of Chromaprint has been released. This is another small release, there are no changes to the core functionality.</p>

<p>Changes since version 1.2:</p>

<ul>
  <li>The binary packages have been built with FFmpeg 2.8.6, adding support for DSF files</li>
  <li>You can use use <code class="language-plaintext highlighter-rouge">fpcalc -length 0</code> to get the full fingerprint</li>
  <li>New function <code class="language-plaintext highlighter-rouge">chromaprint_get_fingerprint_hash</code> for calculating SimHash from the fingerprint data</li>
  <li>Added info section to the fpcalc executable on Mac OS X</li>
  <li>Generate .pc (pkg-config) file on Mac OS X when not building a framework</li>
  <li>Removed use of some long deprecated FFmpeg APIs</li>
  <li>Some smaller bug fixes</li>
</ul>

<p>Download:</p>

<ul>
  <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-1.3.tar.gz">Source code tarball</a> (525 KB)</li>
  <li>Static binaries for the <code class="language-plaintext highlighter-rouge">fpcalc</code> tool
    <ul>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3-win-i686.zip">Windows, 32-bit</a> (1 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3-win-x86_64.zip">Windows, 64-bit</a> (1 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3-osx-i386.tar.gz">Mac OS X, 32-bit, 10.4+</a> (964 KB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3-osx-x86_64.tar.gz">Mac OS X, 64-bit, 10.4+</a> (944 KB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3-linux-i686.tar.gz">Linux, 32-bit</a> (1 MB)</li>
      <li><a href="https://bitbucket.org/acoustid/chromaprint/downloads/chromaprint-fpcalc-1.3-linux-x86_64.tar.gz">Linux, 64-bit</a> (1 MB)</li>
    </ul>
  </li>
</ul>]]></content><author><name>Lukáš Lalinský</name><email>lukas@lalinsky.com</email></author><category term="acoustid" /><category term="acoustid" /><category term="chromaprint" /><category term="release" /><summary type="html"><![CDATA[A new version of Chromaprint has been released. This is another small release, there are no changes to the core functionality.]]></summary></entry></feed>