<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title><![CDATA[bastibe.de]]></title>
<description><![CDATA[bastibe.de]]></description>
<link>https://bastibe.de/</link>
<lastBuildDate>Sun, 15 Oct 2023 11:43:52 +0200</lastBuildDate>
<item>
  <title><![CDATA[Two Years with Legacy Code]]></title>
  <description><![CDATA[
<p>
From January 2021 to the beginning of 2023, I worked on a legacy code base at Fraunhofer IDMT in Oldenburg. My task was the maintenance and development of a DNN-based speech recognition engine that had become terra incognita when its original developer had left the company a year before I started. The code had all the hallmarks of severe technical debt, with layers of half-used abstractions, many unused branches of unknown utility, and the handwriting of several concurrent programmers at odds with each other.
</p>

<p>
The code had evidently been written in a mad dash to bring the product to market. And not to discredit its developers, had been in production for several years, with a core of robust algorithms surrounded by helper scripts that had allowed the company to build upon, even after the original developers had left.
</p>

<p>
It was my job to clean it up. Having spent six years on my PhD recently, I welcomed the calmer waters of 'just' programming for a bit. This blog post is a summary of the sorts of challenges I faced during this time, and what kinds of techniques helped me overcome them.
</p>

<div id="outline-container-orgd38aa96" class="outline-2">
<h2 id="orgd38aa96">The lay of the land</h2>
<div class="outline-text-2" id="text-orgd38aa96">
<p>
I approached the task from the outside, sorting through the build scripts first. Evidently, at least three authors were involved: One old-school Unix geek that wrote an outdated dialect of CMake, one high-level Python scripter, and one shell scripter that deeply believed in abstraction-by-information-hiding. The result of this was&#x2026; interesting.
</p>

<p>
For a good few weeks I "disassembled" these scripts by tracing their execution manually through their many layers, and writing down the necessary steps that were actually executed. My favorite piece of code was a Makefile that called a shell script that ran a Python program, which instantiated a few classes and data structures, which ultimately executed "configure; make; make install" on another underying Makefile. I derived great satisfaction from cutting out all of these middle-men, and consolidating several directories of scripts into a single Makefile.
</p>

<p>
Similar simplifactions were implemented at the same time across several code bases by my colleagues. In due time, this concerted effort enabled us to implement continuous integration, automated benchmarking, and automated builds, but more on that later.
</p>
</div>
</div>

<div id="outline-container-org9562612" class="outline-2">
<h2 id="org9562612">Data refactoring</h2>
<div class="outline-text-2" id="text-org9562612">
<p>
The speech recognition software implemented a sort of interpreter for the DNN layers, originally encoded as a custom binary blob. Apparently, a custom binary approach had been taken to avoid dependencies on external parsing libraries. Yet the data had become so convoluted that both its compilation and its parsing were now considered unchangeable black boxes that impeded further development.
</p>

<p>
Again, I traced through the execution of the compiling code, noted down the pieces of data it recorded, and rewrote the compiler to produce a MsgPack file. On the parsing side, I wrote a custom MsgPack parser in C. Looking back, every job I've had involved writing at least a couple of data dumpers/parsers, yet many developers seem intimidated by such tasks. But why write such a thing yourself instead of using an off-the-shelf solution? In an unrelated code review later in the year one colleague used the cJSON library for parsing JSON; in the event, cJSON was several magnitudes bigger and more complex than the code base it was serving, which is clearly absurd. Our job as developers is to manage complexity, including that of our dependencies. In cases such as these, I often find a simple, fit-for-purpose solution preferable to more generalized external libraries.
</p>

<p>
A part of the DNN data came from the output of a training program. This output however was eternally unstable, often breaking unpredictably between version, and requiring complex workarounds to accommodate different versions of the program. The previous solution to this was a deeply nested decision tree for the various permutations the data could take. I simplified this code tremendously by calling directly into the other program's libraries, instead of trying to make sense of its output. This is another technique I had to rely on several times, hooking into C/C++ libraries from various Python scripts to bridge between data in a polyglot environment.
</p>

<p>
Doing these deep dives into data structures often revealed unintended entanglements. In order to assemble one data structure, you had to grab pieces of multiple different source data. Interestingly, once data structures were cleaned up to no longer have such entanglements, algorithms seemed to fall into place effortlessly. However, this was not a one-step process, but instead an ongoing struggle to keep data structures minimal and orthogonal. While algorithms and functions often feel easier to refactor than data structures, I have learned from this that it is often the changes to data structures that have the greatest effect, and should therefore receive the greatest scrutiny.
</p>
</div>
</div>

<div id="outline-container-orged905b7" class="outline-2">
<h2 id="orged905b7">Code refactoring</h2>
<div class="outline-text-2" id="text-orged905b7">
<p>
My predecessor had left me a few screen casts by way of documentation. While the core program was reasonably well-structured, it was embedded in an architectural curiosity that told the tale of a frustrated high-level programmer forced to do low-level gruntwork. There were poor-man's-classes implemented as C structs with function pointers, there were do-while-with-goto-loops for exception handling, there were sort-of-dynamically-typed data containers, accompanied by angry comments decrying the stupidity of C.
</p>

<p>
Now I like my high-level-programming as much as the next guy, but forcing C to be something it isn't, is not my idea of fun. So over a few months I slowly removed most of these abstractions. Somewhat to my surprise, most of them turned out pure overhead that could simply be removed. Where a replacement was needed, I reverted to native C constructs. Tagged unions instead of casting, variable-length-arrays instead of dynamic arrays. Treating structs as values instead of references. This, alone, reduced the entire code base by a good 10%. The harder part was sorting out the jumble of headers and dependencies that had evidentally built up over time. Together with the removal of dead code paths, the overall code base shrank by almost half. There are few things more satisfying than excising and deleting unnecessary code.
</p>

<p>
I stumbled upon one particularly interesting problem when trying to integrate another code base into ours. Within our own software, build times were small enough to make logging and printf-debugging easier than an interactive debugger such as GDB. The other code base however was too complex to recompile on a whim, and a different solution had to be found. Now I am a weird person who likes to touch the raw command line instead of an IDE. And in this case this turned out to be a huge blessing, as I found that GDB can not only be used interactively, but can also be scripted! So instead of putting logging into the other library, I wrote GDB scripts that augmented break points with a little <code>call printf(...)</code> or <code>print/d X</code>. These could get suprisingly complicated, where one breakpoint might enable or disable other breakpoints conditionally, and break point conditions could call functions on their own. It took some learning, but these debugging scripts were incredibly powerful, and a technique I will definitely refer to in the future.
</p>

<p>
When adding new features to the software, I often found it impossible to work the required data flow into the existing program code without snowballing complexity. I usually took these situations as code smells that called for a refactoring. Invariably, each cleaning up of program flow or data structures inched the program closer and closer to allow my feature addition. After a while, this became an established modus operandi: independently clean the code until feature additions become easy and obvious, then do the obvious thing. Thus every task I finished also left the surrounding code in a better state. In the end, about 80% of the code base had gotten this treatment, and I strongly believe that this has left the project in a much better state than it was before. To say nothing of the added documentation and tests, of course.
</p>
</div>
</div>

<div id="outline-container-org526d592" class="outline-2">
<h2 id="org526d592">More velocity makes bigger craters</h2>
<div class="outline-text-2" id="text-org526d592">
<p>
As I slowly shifted from cleanup work to new features, change management became a pressing issue. New features had to be evaluated, existing features had to be tested, and changes had to be documented and downstreamed. Fascinatingly, the continuous integration and evaluation tools we built for this purpose, soon unearthed a number of hidden problems in other parts of the product that we had not been aware of (including that the main task I had been hired to do was less worthwhile than thaught, LOL). That taught us all a valuable lesson about testing, and proving our assertions. That said, I never found bottom-level unit tests all that useful for our purposes; the truly useful tests invariably were higher-level integration tests.
</p>

<p>
Eventually, my feature additions led to downstream changes by several other developers. While I took great care to present a stable API, and documenting all changes and behavior appropriately, at the end of the day my changes still amounted to a sizeable chunk of work for others. This was a particularly stark contrast to the previous years of perfect stagnation while nobody had maintained the library. My main objective at this point was to avoid the mess I had started out with, where changes had evidentally piled on changes until the whole lot had become unmaintainable.
</p>

<p>
Thus a balance had to be struck between moving fast (and breaking things), and projecting stability and dependability. One crucial tool for this job turned out to be code reviews. By involving team members directly with the code in question, they could be made more aware of its constraints and edge cases. It took a few months to truly establish the practice, but by the end of a year everyone had clearly found great value in code reviews as a tool for communication.
</p>
</div>
</div>

<div id="outline-container-org658ca5c" class="outline-2">
<h2 id="org658ca5c">Conclusions</h2>
<div class="outline-text-2" id="text-org658ca5c">
<p>
There is a lot more to be said about my time at Fraunhofer. The deep dive into the world of DNN engines was truly fascinating, as were the varied challenges of implementing these things on diverse platforms such as high-performance CPU servers, Laptops, Raspberry Pis, and embedded DSPs. I learned to value automation of developer tasks, and of interface stability and documentation for developer productivity.
</p>

<p>
But most of all, I learned to appreciate legacy code. It would have been easy to call it a "mess", and advocate to rewrite it from scratch. But I found it much more interesting to try to understand the code's heritage, and tease out the algorithmic core from the abstractions and architectural supports. There were many gems to be found this way, and a lot to be learned from the programmers before you. I often felt a strange connection to my predecessor, as if we were talking to each other through this code base. And no doubt my successor feels the same way about my code now.
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <link>https://bastibe.de/2023-10-15-one-year-with-legacy-code.html</link>
  <guid>https://bastibe.de/2023-10-15-one-year-with-legacy-code.html</guid>
  <pubDate>Sun, 15 Oct 2023 15:01:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[OS Customization and MacOS]]></title>
  <description><![CDATA[
<p>
I was an Apple fanboy some years ago. Back then, whenever something was odd on my computer, I was
surely just using it wrong. Nowadays, I see things the other way around: We're not "holding it
wrong", the computer is just defective. Computers should do our bidding, not vice versa. So here's a
bunch of things that I do to my computers to mold them to my way of working.
</p>

<div id="outline-container-orga6f6339" class="outline-2">
<h2 id="orga6f6339">Keyboard Layout</h2>
<div class="outline-text-2" id="text-orga6f6339">
<p>
I switch constantly between a German and English keyboard layout, and regularly between various
machines. My physical keyboards are German, and my fingers are used to the Windows-default German and
(international) US keyboard layout. These are available by default on Windows and Linux, but MacOS
goes its own way.
</p>

<p>
However, keyboard layouts on MacOS are saved in relatively simple text files, and can be modified
with relative ease. The process goes like this: Download <a href="https://software.sil.org/ukelele/">Ukelele (free)</a> to create a new keyboard
layout bundle for your base layout<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>. Inside that bundle, there's a <i>*.keylayout</i> file,
which is an XML file that defines the characters that each key-modifier combination produces. I
changed that to create a Windows-like US keyboard layout. And I replaced the keyboard icon with
something sane (not "A") by creating a 256x256 pixel PNG, opening it in Preview, holding alt while
saving to select the ICNS format. Save the keyboard bundle to <code>~/Library/Keyboard Layouts</code> and
reboot. Then I remove the unremovable default ("A") German layout by selecting another one, then
<code>plutil -convert xml1 ~/Library/Preferences/com.apple.HIToolbox.plist</code>, and delete the entry from
<code>AppleEnabledInputSources</code>. Now reboot. Almost easy. Almost.
</p>

<p>
One the one hand, this was quite the ordeal. On the other, I have tried to do this sort of thing on
Windows and Linux before, and for the life of me <i>could not do it</i>. So I actually think this is
great!
</p>
</div>
</div>

<div id="outline-container-org02f475a" class="outline-2">
<h2 id="org02f475a">Keyboard Shortcuts</h2>
<div class="outline-text-2" id="text-org02f475a">
<p>
My main text editor is Emacs, and I am very used to its keyboard shortcuts. Of particular note are
CTRL-A/E for going to the beginning/end of a line, and Alt-B/F for navigating forward/backwards by
word. I have long wanted to use these shortcuts not just in Emacs and readline-enabled terminal
applications, but everywhere else, too. And with MacOS, this is finally possible: Install
<a href="https://folivora.ai/">BetterTouchTool ($22)</a>, and create keyboard shortcuts that maps, e.g. Alt-B/F to Alt-←/→. Ideally,
put this in a new activation group that excludes Emacs. It may be necessary to remove the keyboard
character for Alt-B/F from your keyboard layout before this works. I've spent an embarrassing number
of hours trying to get this to work on Windows and Linux, and really got nowhere<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup>.
Actually, however, most readline shortcuts such as Ctrl-A/E/B/F/K/Y already work out of the box on
MacOS!
</p>
</div>
</div>

<div id="outline-container-orga52c334" class="outline-2">
<h2 id="orga52c334">Mouse Configuration</h2>
<div class="outline-text-2" id="text-orga52c334">
<p>
I generally use a trackpad, and occasionally a traditional mouse for image editing, and have used a
trackball. I find that any one specific device will lead to wrist pain if used constantly, so I
switch it up every now and then. The trackpad and trackball, however, need configuration to be
usable.
</p>

<p>
After experimenting with many a trackpad device, I have found Apple touch pads the best trackpads on
the market<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup>. On MacOS, they lacks a middle mouse click. So I created a trackpad
shortcut in the aforementioned <a href="https://folivora.ai/">BetterTouchTool ($22)</a> to map the middle click on a three-finger tap
(can also be had for free with <a href="https://github.com/artginzburg/MiddleClick-Ventura">MiddleClick (OSS)</a>). For Windows, <a href="https://magicutilities.net/">Magic Utilities ($17/y)</a> provides a
wonderful third-party driver for Apple devices that also supports the three-finger tap. I have not
gotten the Apple touch pad to pair reliably on Linux, and have generally found their touch pad
driver <i>libinput</i> a bit lacking.
</p>

<p>
My trackball is a Kensington SlimBlade. To scroll, you rotate the ball around its vertical axis.
This is tedious for longer scroll distances, however. But there's an alternative scrolling method
called "button scrolling", where you hold one button on the trackball, and move the ball to scroll.
You need to install the Kensington driver to enable this on Windows and MacOS. Button scrolling is
available on Linux as well using xinput<sup><a id="fnr.4" class="footref" href="#fn.4" role="doc-backlink">4</a></sup>, but I haven't gotten the setting to stick across
reboots or sleep cycles. So I wrote a background task that checks xinput every five seconds,
which does the trick.
</p>
</div>
</div>

<div id="outline-container-orgee58501" class="outline-2">
<h2 id="orgee58501">Window Management</h2>
<div class="outline-text-2" id="text-orgee58501">
<p>
Frankly, Windows does window management correctly. Win-←/→ moves windows to the left and right edge
of the screen, as does dragging the window to the screen border. Further Win-←/→ then moves the
window to the next half-screen in that direction, even across display boundaries. KDE does this
correctly out of the box as well, Gnome does not do the latter, and it drives me mad. MacOS doesn't
do any of these things. But <a href="https://rectangleapp.com/">Rectangle (OSS)</a> does. Easy fix. (BetterTouchTool can do it, too, but
Rectangle is prettier)
</p>

<p>
Furthermore, I want Alt-Tab to switch between windows. Again, MacOS is the odd one out, which uses
CMD-Tab to switch between <i>apps</i>, now windows. And then there's another shortcut for switching
between windows of the same app, but the shortcut really doesn't work at all on a German keyboard.
Who came up with this nonsense? Anyway, <a href="https://manytricks.com/witch/">Witch ($14)</a> implements window switching properly.
</p>
</div>
</div>

<div id="outline-container-org328c61c" class="outline-2">
<h2 id="org328c61c">Application Management</h2>
<div class="outline-text-2" id="text-org328c61c">
<p>
In Windows and Linux, I hit the Windows key and start typing to select and start an app. In MacOS,
this is usually Cmd-Space, but BetterTouchTool can map it to a single short Cmd, if you prefer.
</p>

<p>
More annoying are the various docks and task bars. I always shove the dock off to the right edge of
the screen, where it stays out of the way. Windows 10 had a sane dock, but then 11 came and forced
it to the bottom of the screen. Dear OS makers, every modern screen has plenty of horizontal space.
But vertical space is somewhat limited. So why on earth would you make a rarely used menu such as
the dock consume that precious vertical space by default? And Microsoft, specifically, <i>why not make
it movable</i>? Thankfully, there's <a href="https://www.startallback.com/">StartAllBack ($5)</a>, which replaces the Windows task bar with
something sensible, and additionally cleans up the start menu if you so desire. On KDE, I
fractionally prefer <a href="https://github.com/KDE/latte-dock">Latte (OSS)</a> over KDE's native dock. The MacOS dock is uniquely dumb, offering no
start menu, and allowing no window selections. But it's unobtrusive and can be moved to the right
edge, so it's not much of a bother.
</p>
</div>
</div>

<div id="outline-container-org92c217e" class="outline-2">
<h2 id="org92c217e">File Management</h2>
<div class="outline-text-2" id="text-org92c217e">
<p>
One of the most crucial tasks in computer work in general is file management. I am not satisfied
with most file managers. Dolphin on KDE works pretty well, it has tabs, can bulk-rename files, can
display large directories without crashing, and updates in real time when new files are added to the
current directory. Gnome Nautilus is so bad it is the main reason I switched to KDE on my Linux
machines. Finder on MacOS is passable, I suppose, although the left sidebar is unnecessarily
restrictive (why can't I add a shortcut to a network drive?). Windows Explorer is really rather
terrible, lacking a bulk-rename tool, and crucially, tabs. In Windows 10, these can be added with
<a href="https://www.stardock.com/products/groupy/">Groupy ($12)</a> (set it to only apply to explorer.exe). Windows 11 has very recently added native tabs,
which work OK, but can't be detached from the window.
</p>

<p>
The sad thing is that there are plenty of very good file manager replacements out there, but none of
the OSs have a mechanism for replacing their native file manager in a consistent way, so we're
mostly stuck with the defaults.
</p>

<p>
Oh, and I always remove the iCloud/OneDrive sidebar entries, which is <a href="https://www.howtogeek.com/225973/how-to-disable-onedrive-and-remove-it-from-file-explorer-on-windows-10/">surprisingly tedious</a> on
Windows.
</p>
</div>
</div>

<div id="outline-container-orgd9caebd" class="outline-2">
<h2 id="orgd9caebd">Hardware Control</h2>
<div class="outline-text-2" id="text-orgd9caebd">
<p>
On laptops, you can control screen brightness from your keyboard. On desktops, you can not. However,
some clever hackers have put together <a href="https://github.com/waydabber/BetterDisplay#readme">BetterDisplay (OSS for screen brightness)</a>, which adds this
capability to MacOS. That's actually a capability I have wanted for quite a while, and apparently it
is only available in MacOS. Great stuff!
</p>

<p>
Less great is that MacOS does not allow volume control on external sound cards. <a href="https://rogueamoeba.com/soundsource/">SoundSource ($47)</a>
adds this rather crucial functionality back, once you go through the unnecessarily excruciating
process of enabling custom kernel extensions. Windows and Linux of course natively support this.
</p>

<p>
Another necessary functionality for me is access to a non-sucky (i.e. no FAT) cross-platform file
system. At the moment, the most portable file system seems to be NTFS, of all things. Regrettably,
MacOS only supports <i>reading</i> NTFS, but no writing. <a href="https://www.paragon-software.com/home/ntfs-mac/#">Paragon NTFS (€20)</a> adds this with another kernel
extension, and promptly kernel-panicked my computer. Oh joy. At least it's only panicking for file
transfers initiated by DigiKam, which I can work around. Paragon Support says they're working on it.
I'm not holding my breath. Windows and Linux of course natively support NTFS.
</p>
</div>
</div>

<div id="outline-container-org672cc57" class="outline-2">
<h2 id="org672cc57">System Management</h2>
<div class="outline-text-2" id="text-org672cc57">
<p>
I have learned from experience not to trust graphical backup programs. TimeMachine in particular has
eaten my backups many times already, and can not be trusted. But I have used <a href="https://www.borgbackup.org/">Borg (OSS)</a> for years,
and it has so far performed flawlessly. Even more impressive, my Borg backups have a continuous
history despite moving operating systems several times. It truly is wonderful software!
</p>

<p>
On Windows, I run Borg inside the WSL, and schedule its backups with the Windows Task Scheduler. On
Linux, I schedule them with systemd units. On MacOS, I install Borg with <a href="https://brew.sh/">Homebrew (OSS)</a> and schedule
the backups with launchd tasks. It's all pretty equivalent. One nice thing about launchd, however,
is how the OS immediately pops up a notification if there's a new task file added, and adds the task
to the graphical system settings.
</p>

<p>
I have to emphasize what a game-changer the WSL is on Windows. Where previously, such simple
automations where a pain in the neck to do reliably, they're now the same simple shell scripts as on
other OSes. And it perfectly integrates with Windows programs as well, including passing pipes
between Linux and Windows programs. It's truly amazing! At the moment, I'd rate Windows a better
Unix system than MacOS for this reason. Homebrew is a passable package manager on MacOS, but the way
it's ill-integrated into the main system (not in system PATH) is a bit off-putting.
</p>
</div>
</div>

<div id="outline-container-orgb305643" class="outline-2">
<h2 id="orgb305643">App Compatibility</h2>
<div class="outline-text-2" id="text-orgb305643">
<p>
I generally use my computer for three tasks: General document stuff, photo editing, and video games.
</p>

<p>
One major downside of Apple computers is that video games aren't available. This has become less of
a problem to me since I bought a Steam Deck, which has taken over gaming duties from my main PC.
Absolutely astonishingly, the Steam Deck runs Windows games on <i>Linux</i> through emulation, which
works almost flawlessly, making video games no longer a Windows-only proposition.
</p>

<p>
What doesn't work well on Linux are commercial applications. Wine generally does not play well with
them, and frustratingly for my photo editing, neither <a href="https://www.vmware.com/products/workstation-player.html">VMWare Workstation Player (free)</a> nor
<a href="https://www.virtualbox.org/">VirtualBox (OSS)</a> support hardware-accelerated VMs on up-to-date Linux<sup><a id="fnr.5" class="footref" href="#fn.5" role="doc-backlink">5</a></sup>. So where MacOS lacks
games, Linux lacks Photoshop. Desktop applications in general tend to be unnecessarily cumbersome to
manage and update on Linux. Flatpak is helping in this regard, by installing user-facing
applications outside of the OS package managers, but it remains more work than on Windows or MacOS.
The occasional scanner driver or camera interface app can also be troublesome on Linux, but that's
easily handled with a VirtualBox VM (with the proprietary <i>Extension Pack</i> for USB2 support), and
hasn't really bothered me too much.
</p>

<p>
Luckily for me, my most-used apps are generally OSS tools such as <a href="https://www.darktable.org/">Darktable (OSS)</a> and <a href="https://www.digikam.org/">DigiKam (OSS)</a>,
or cross-platform programs like <a href="https://fishshell.com/">Fish (OSS)</a>, <a href="https://git-scm.com/">Git (OSS)</a>, and <a href="https://www.gnu.org/software/emacs/">Emacs (OSS)</a>. This is however, where
Windows has a bit of a sore spot, as these programs tend to perform noticeably worse on Windows than
on other platforms. Emacs and git in particular are just terribly slow on Windows, taking several
seconds for routine operations that are <i>instant</i> on other platforms. That's probably due to
Windows' rather slow file system and malware scanner for the many-small-files style of file
management that these Unix tools implement. It is very annoying.
</p>
</div>
</div>

<div id="outline-container-orgc4dec82" class="outline-2">
<h2 id="orgc4dec82">Conclusions</h2>
<div class="outline-text-2" id="text-orgc4dec82">
<p>
So there's just no perfect solution. MacOS can't do games, Linux can't run commercial applications,
and Windows is annoyingly slow for OSS applications. Regardless, I regularly use all three systems
productively. My job is mostly done on Windows, my home computer runs MacOS, and my Steam Deck and
automations run Linux.
</p>

<p>
Overall, I currently prefer MacOS as my desktop OS. It is surprisingly flexible, and more scriptable
than I thought, and in some ways is actually more functional than Linux or Windows. The integrated
calendar and contacts apps are nice, too, and not nearly as terrible as their Windows/Linux
counterparts. To say nothing of the amazing M1 hardware with its minuscule power draw and total
silence, while maintaining astonishing performance.
</p>

<p>
Linux is where I prefer to program, due to its sane command line and tremendously good
compiler/debugger/library infrastructure. As a desktop OS, it does have some rough edges, however,
especially for its lack of access to commercial applications. While Linux <i>should</i> be the most
customizable of these three, I find things tend to break too easily, and customizations are often
scattered widely between many different subsystems, making them very hard to get right.
</p>

<p>
Theoretically, Windows is the most capable OS, supporting apps, OSS, and games. But it also feels
the most user-hostile of these three, and the least performant. And then there's the intrusive ads
everywhere, its spying on my every move, and at work there's inevitably a heavy-handed administrator
security setup that gets in the way of productivity. It's honestly fine on my home computer, at
least since they introduced the WSL. But using it for work every day is quite enough, so I don't
want to use it at home, too.
</p>
</div>
</div>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
if there's an easier way to create a keyboard layout bundle, please let me know. I
didn't use ukelele for anything but the bundle creation.
</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
It occurs to me that it might actually be possible to do something like on Windows
this with <a href="https://www.autohotkey.com/">AutoHotkey (free)</a>. I'll have to try that!
</p></div></div>

<div class="footdef"><sup><a id="fn.3" class="footnum" href="#fnr.3" role="doc-backlink">3</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
The Logitech T650 is actually not bad, but the drivers are a travesty. Some Wacom
tablets include touch, too, but they palm rejection is abysmal and they don't support gestures.
</p></div></div>

<div class="footdef"><sup><a id="fn.4" class="footnum" href="#fnr.4" role="doc-backlink">4</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
<code>xinput set-prop "Kensington Slimblade Trackball" "libinput Scroll Method Enabled" 0, 0, 1 # button scrolling</code> <br>
<code>xinput set-prop "Kensington Slimblade Trackball" "libinput Button Scrolling Button" 8 # top-right button</code>
</p></div></div>

<div class="footdef"><sup><a id="fn.5" class="footnum" href="#fnr.5" role="doc-backlink">5</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
VirtualBox does not have a good accelerated driver, and VMWare does not support recent
kernels. Qemu <i>should</i> be able to solve this problem, but I couldn't get it to work reliably.
</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-computers.html">computers</a> <a href="https://bastibe.de/tag-linux.html">linux</a> <a href="https://bastibe.de/tag-macos.html">macos</a> <a href="https://bastibe.de/tag-windows.html">windows</a> ]]></description>
  <category><![CDATA[computers]]></category>
  <category><![CDATA[linux]]></category>
  <category><![CDATA[macos]]></category>
  <category><![CDATA[windows]]></category>
  <link>https://bastibe.de/2023-04-21-os-customization-and-macos.html</link>
  <guid>https://bastibe.de/2023-04-21-os-customization-and-macos.html</guid>
  <pubDate>Fri, 21 Apr 2023 10:19:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Media of 2022]]></title>
  <description><![CDATA[
<p>
Around this time of the year, I usually write a blog post about my
favorite books of the last year. But this time, not enough of them
really stood out. So instead, here's my favorite pieces of media I
consumed in the last year:
</p>

<div id="outline-container-orge02abd4" class="outline-2">
<h2 id="orge02abd4"><a href="https://www.goodreads.com/book/show/57007979-firepower">Firepower</a></h2>
<div class="outline-text-2" id="text-orge02abd4">
<figure style="float:left">
<img src="/static/2023-02/firepower cover.jpg" alt="book cover for Firepower" width="150px"/>
</figure>

<p>
This is the story of how gunpowder changed the world. We get to see
the familiar history of central Europe, but told unusually, from the
bottom up: how seemingly small inventions change the course of peoples
and nations. The book is in essence a history of warfare in the last
few hundred years, but this time the movers and shakers are not <a href="https://en.wikipedia.org/wiki/Great_man_theory">Great
Men</a>, but chemistry and engineering. A fascinating perspective, to say
the least.
</p>

<p>
Along the way, the book unraveled countless tangents and quirks I had
previously stumbled upon, yet never understood. How castles went from
tall walled structures to flat earthworks in the 18th century due to
the disruptive invention of cannons. How wooden galleons of 1850 were
obsoleted by turreted iron warships practically overnight. How rifling
and shells bled dry the coffers of Central Europe and made conflict
inevitable. This book contextualized many a story like this in the
most riveting manner!
</p>
</div>
</div>

<div id="outline-container-org75509c5" class="outline-2">
<h2 id="org75509c5"><a href="https://www.steamdeck.com/">Steam Deck</a></h2>
<div class="outline-text-2" id="text-org75509c5">
<figure style="float:left">
<img src="/static/2023-02/steam deck.webp" alt="steam deck controller" width="290px"/>
</figure>


<p>
Ever since we had our second child, I didn't really find the time for
video games any more, much to my regret. So when the Steam Deck was
announced, essentially a portable gaming computer, it didn't feel like
a worthwhile investment.
</p>

<p>
But boy, was I wrong about that. The genius of the Steam Deck is how
it's instantly-on, instantly-off like a video games console, allowing
me to play in short bursts that would not otherwise be available to
gaming. But in contrast to a console, the deck allows me to play games
without blocking the living room, and away from the computer screen
I'm working at all day anyway.
</p>

<p>
It has reignited my video gaming, and surprisingly not just for newer
titles, but thanks to <a href="https://www.emudeck.com/">EmuDeck</a>, emulated retro games as well. I had a
blast playing Banjo-Kazooie with my daughter, and Chorus, Ace Combat,
Guardians of the Galaxy and Death Stranding on my own. To me, this is
a revolutionary device, and I haven't touched my gaming PC or any of
my video game consoles since!
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-books.html">books</a> <a href="https://bastibe.de/tag-media.html">media</a> ]]></description>
  <category><![CDATA[books]]></category>
  <category><![CDATA[media]]></category>
  <link>https://bastibe.de/2023-02-12-books-of-2022.html</link>
  <guid>https://bastibe.de/2023-02-12-books-of-2022.html</guid>
  <pubDate>Sun, 12 Feb 2023 15:02:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[RAW Developer Comparison 2]]></title>
  <description><![CDATA[
<p>
It's that time of the year again when all image editing programs come out with new versions. This comes at an inopportune time, as I feel restless of late. So, naturally, I had to try them all. Or maybe I just wanted a justification for buying DxO PhotoLab, because people on the internet speak so well of it 🙄.
</p>

<p>
For the following comparison I downloaded trial versions of <a href="https://www.acdsee.com">ACDSee Photo Studio Ultimate 2023</a> (€155), <a href="https://www.captureone.com/">Capture One 22</a> (€350 or €220/a), <a href="https://www.darktable.org/">Darktable 4.0</a> (free), <a href="https://www.dxo.com/">DxO Photolab 6</a> (€220 + €140 for FilmPack 6 + €99 for ViewPoint), <a href="https://www.adobe.com/products/photoshop-lightroom-classic.html">Adobe Lightroom Classic 11.5</a> (€142/a), <a href="https://www.on1.com/">ON1 Photo Raw 2023</a> (€126), <a href="https://rawtherapee.com/">RawTherapee 5.8</a> (free), <a href="https://silkypix.isl.co.jp/en/">Silkypix Developer Studio Pro 11</a> (€155), <a href="https://exposure.software/">Exposure X7</a> (€165), and <a href="https://www.zoner.com/">Zoner Photo Studio X Fall 2022</a> (€60/a). I also installed <a href="https://skylum.com/luminar">Luminar Neo</a> (€120 or €80/a) and <a href="https://radiantimaginglabs.com/">Radiant Photo</a> (€140) but I disliked them so immediately and viscerally that I didn't include them in the comparison below.
</p>

<p>
In order to put them through their paces, I took a random smattering of images from the last few years that I found difficult to work with for one reason or another, and checked how each of the programs dealt with them. Of course I am no expert in any of them except Darktable and Capture One, so my results are probably flawed. I tried to inject some objectivity by limiting my edits to the most obvious sliders wherever possible, especially in the programs I know better. Regardless, my comparison is probably less scientific than <a href="https://bastibe.de/2020-05-01-raw-developer-comparison.html">last time</a>, because my brain sort of broke after staring at too many renderings of the same images for too long. Don't try this at home, folks!
</p>

<div id="outline-container-org3b17335" class="outline-2">
<h2 id="org3b17335">Test Case One: Fire</h2>
<div class="outline-text-2" id="text-org3b17335">
<p>
Fire is notoriously difficult to deal with, because it covers a large dynamic range, and we have strong associations of certain colors with heat. Thus a more yellow rendering usually suits fire very well, whereas a more neutral rendering quickly looks unnatural. In particular, we seem to expect highlights to twist to yellow, and midtones to remain orange.
</p>

<p>
My editing goals for this picture are simple: raise <i>shadows</i> or <i>blacks</i> until the pan becomes faintly visible, and reign in highlights if necessary to prevent excessive clipping.
</p>

<br>
  <div class="lightbox" style="height: 200px">
    <figure>
      <img src="/static/2022-10/DSCF9359_acd.thumb.jpg">
      <figcaption>ACDSee Photo Studio<br>
      highlights turn strongly yellow</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF9359_c1.thumb.jpg">
      <figcaption>Capture One<br>
      highlights turn yellow<br>
      shadows adjusts unusally far into midtones</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF9359_dt_v6.thumb.jpg">
      <figcaption>Darktable (filmic v6)<br>
      highlights turn desaturate<br>
      weirdly salmon color<br>
      filmic v6, zero latitude, no color preservation<br>
      tone EQ very unusual re: shadows/blacks sliders</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF9359_dt_v5.thumb.jpg">
      <figcaption>Darktable (filmic v5)<br>
      highlights turn yellow<br>
      filmic v5, zero latitude, no color preservation<br>
      tone EQ very unusual re: shadows/blacks sliders</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF9359_dxo.thumb.jpg">
      <figcaption>DxO PhotoLab<br>
      highlights desaturate</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF9359_lr.thumb.jpg">
      <figcaption>Lightroom Classic<br>
      highlights desaturate</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF9359_on1.thumb.jpg">
      <figcaption>ON1 Photo RAW<br>
      highlights turn very yellow<br>
      pan immediately visible without adjustments</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF9359_rt.thumb.jpg">
      <figcaption>RawTherapee<br>
      highlights desaturate</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF9359_sp.thumb.jpg">
      <figcaption>Silkypix Developer<br>
      highlights turn yellow, but lose all definition<br>
      shadows slider not strong enough to show pan</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF9359_x7.thumb.jpg">
      <figcaption>Exposure X7<br>
      highlights turn unpleasant white<br>
      raising shadows turns background off-black</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF9359_zp.thumb.jpg">
      <figcaption>Zoner Photo Studio<br>
      highlights desaturate<br>
      weird, clarity-like effect</figcaption>
    </figure>
  </div>
<p>Fujifilm X-Pro2 with XF35mmF1.4 R 1/1000s f/2.2 ISO400<br><a href="/static/2022-10/DSCF9359.RAF">&#x1f4c2; DSCF9359.RAF</a> (23.0 MB) <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/80x15.png" /></a></p>

<p>
There's a difficult tradeoff to be made here: Fire highlights physically don't change hue much compared to the fire body, but we visibly expect "hotter" fire to twist yellow. So a balance has to be struck between merely desaturating highlights, and twisting them yellow. You can see Darktable v6, DxO PhotoLab, RawTherapee, Exposure, and Zoner leaning towards desaturation, while the others render yellow color twists of some form or another. ACDSee and ON1 probably take the yellow a bit too far.
</p>

<p>
However, there's a flip side to this: Every program that renders yellow highlights in fire, does the same for overexposed skin, twists overexposed skies cyan, and red flowers magenta. It's a difficult tradeoff to get right. This is especially tricky since color shifts in highlights are often baked deeply into the programs' color science, and hard to get rid off where they're unwanted.
</p>

<p>
Anyway, to my eyes, the only fire-like renderings here come from Capture One, Darktable v5, PhotoLab, and Lightroom.
</p>
</div>
</div>

<div id="outline-container-orgdebfa0e" class="outline-2">
<h2 id="orgdebfa0e">A Hazy Mountain</h2>
<div class="outline-text-2" id="text-orgdebfa0e">
<p>
This lovely scene is a deep crop into an image taken at long distance on a hazy day. The challenge is therefore <i>dehazing</i> the mountains, chiseling out the contours with <i>clarity</i> and <i>texture</i> and <i>contrast</i>, and removing any extraneous noise.
</p>

<p>
This is a difficult task, as emphasizing local contrast tends to produce halos near the horizon, dehazing tends to introduce unpleasant color shifts, and the deep crop necessitates a subtle balance between denoising and detail retention.
</p>

<br>
  <div class="lightbox" style="height: 200px">
    <figure>
      <img src="/static/2022-10/DSF4442_acd.thumb.jpg">
      <figcaption>ACDSee Photo Studio<br>
      strong halos from clarity/texture<br>
      very inefficient/smeary denoising</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSF4442_c1.thumb.jpg">
      <figcaption>Capture One<br>
      very little dehaze used, as higher settings break tonality<br>
      little definition in shadows</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSF4442_dt.thumb.jpg">
      <figcaption>Darktable<br>
      very little default saturation, easy to fix<br>
      outstandingly subtle rendering to my eye</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSF4442_dxo.thumb.jpg">
      <figcaption>DxO PhotoLab<br>
      dehaze ("ClearView") produces strong hue shift<br>
      clarity ("Microcontrast") is very slow<br>
      contrast not enough editing range, added tone curve to help<br>
      denoise ("DeepPrime") annoyingly only visible in mini viewer</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSF4442_lr.thumb.jpg">
      <figcaption>Lightroom Classic<br>
      dehaze works perfectly!<br>
      denoise not very effective and slightly wormy<br>
      tends to strong halos from clarity</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSF4442_on1.thumb.jpg">
      <figcaption>ON1 Photo RAW<br>
      dehaze produces strong hue shift<br>
      strong halos on the horizon<br>
      highlights tend to blow to pure white somehow</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSF4442_rt.thumb.jpg">
      <figcaption>RawTherapee<br>
      dehaze produces hue shift that is hard to fix<br>
      does not hide cropped-out image?</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSF4442_sp.thumb.jpg">
      <figcaption>Silkypix Developer<br>
      pleasant rendering, but not very detailed<br>
      there does not seem to be a clarity-like slider?</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSF4442_x7.thumb.jpg">
      <figcaption>Exposure X7<br>
      works very well in this image</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSF4442_zp.thumb.jpg">
      <figcaption>Zoner Photo Studio<br>
      weirdly ineffective dehaze<br>
      contrast introduces strong saturation<br>
      ineffective and wormy denoising</figcaption>
    </figure>
  </div>
<p>Fujifilm X-T2 with XF70-300 @ 231mm 1/400s f/5.7 ISO200<br><a href="/static/2022-10/DSF4442.RAF">&#x1f4c2; DSF4442.RAF</a> (23.0 MB) <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/80x15.png" /></a></p>

<p>
Overall, most of these renderings turned out fine. But there are pretty substantial differences in denoising, haloing, and detail retention of the shadows specifically. Halos especially are a personal bug-bear of mine, where the sky above the horizon line brightens and (worse) the mountains below the horizon line darken. This is especially visible in ACDSee, ON1, and Zoner, and to a lesser extent in DxO, Lightroom, and RawTherapee.
</p>

<p>
There were also significant differences in noise removal. Especially ACDSee, Exposure, and Zoner had weirdly ineffective denoising, and were unusually difficult to balance against smearing and worms in Lightroom, ON1, and Silkypix. Colors were a bit difficult to control in ACDSee, ON1, and RawTherapee.
</p>

<p>
The most pleasant renderings to my eye are DxO, Exposure, and Darktable in this round, although many of the others are very usable as well.
</p>
</div>
</div>

<div id="outline-container-org3281eab" class="outline-2">
<h2 id="org3281eab">High Key Rendering</h2>
<div class="outline-text-2" id="text-org3281eab">
<p>
Contrary to the popular style at moment, I sometimes like my highlights a little blown. I especially like a smooth, desaturated, film-like drop-off in my highlights, which seems strangely difficult to replicate in digital photography.
</p>

<p>
So instead of turning the following picture into an HDR hellscape, I want to compress the bright background into the highlights, while expanding the dark foreground to fill the midtones. The capture actually has all highlight information intact, so I don't want to blow anything out completely, just gracefully fade it into pastels.
</p>

<br>
  <div class="lightbox" style="height: 200px">
    <figure>
      <img src="/static/2022-10/DSCF0190_acd_safe.thumb.jpg">
      <figcaption>ACDSee Photo Studio<br>
      nice highlight rendering<br>
      very blotchy noise reduction in the shadows</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF0190_c1_safe.thumb.jpg">
      <figcaption>Capture One<br>
      weirdly saturated trees<br>
      very noisy foreground</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF0190_dt_safe.thumb.jpg">
      <figcaption>Darktable<br>
      default rendering horrendous<br>
      setting color preservation to luminance helps<br>
      weirdly saturated trees<br>
      very noisy foreground</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF0190_dxo_safe.thumb.jpg">
      <figcaption>DxO PhotoLab<br>
      oversaturated by default (easy to fix)<br>
      good foreground brightness by default<br>
      strangly contrasty highlights</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF0190_lr_safe.thumb.jpg">
      <figcaption>Lightroom Classic<br>
      trees remain unrealistically dark<br>
      noisy foreground</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF0190_on1_safe.thumb.jpg">
      <figcaption>ON1 Photo RAW<br>
      trees remain unrealistically dark<br>
      unsightly HDR look</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF0190_rt_safe.thumb.jpg">
      <figcaption>RawTherapee<br>
      terribly oversaturated trees</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF0190_sp_safe.thumb.jpg">
      <figcaption>Silkypix Developer<br>
      shadows does not raise black point, remains dark<br>
      weird color areas in the sky</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF0190_x7_safe.thumb.jpg">
      <figcaption>Exposure X7<br>
      strange color fringes on trees<br>
      highlights hard to deal with</figcaption>
    </figure>
    <figure>
      <img src="/static/2022-10/DSCF0190_zp_safe.thumb.jpg">
      <figcaption>Zoner Photo Studio<br>
      noisy foreground</figcaption>
    </figure>
  </div>
<p>Fujifilm X-Pro2 with XF16-80mm @ 16mm 1/400s f/9 ISO400<br>(no raw, for privacy reasons)</p>

<p>
The different renderings of this image are more of a matter of preference than any of the previous ones. To my eyes, I like the versions drawn by ACDSee, Capture One, Zoner Photo, and DxO PhotoLab best, and I recon that many of the other versions could have been improved with a little more manual tuning. The only problematic versions of this image were the strange HDR-like ON1 render, and the Silkypix variant with its lost black point.
</p>
</div>
</div>

<div id="outline-container-orgf15c2c6" class="outline-2">
<h2 id="orgf15c2c6">Summary</h2>
<div class="outline-text-2" id="text-orgf15c2c6">
<p>
Overall, all of these programs seem reasonable tools for image editing. Most of their differences can probably be overcome if you learn them better. That said, this comparison has left me with a few clear favorites. To be clear, the above comparison only showed the most decisive images of a much larger set which informs my opinion. It should also be noted that my tastes in image editing do not focus on detail recovery, detailed masking, nontrivial retouching, or scene-changing edits such as wholesale sky swapping.
</p>

<p>
One area I am particularly interested in, however, is the inherent complexity of the editing tools: For example, I like my <i>saturation</i> slider to only change saturation and leave lightness alone. Similarly, <i>contrast</i> adjustments should not affect saturation. Another interesting part is the behavior of <i>highlights</i> adjustments. Ideally, I'd like <i>highlights</i> to be able to counteract <i>exposure</i> adjustments so I can balance them against one another. Better yet if the same can be done with the <i>tone curve</i>.
</p>

<table>


<colgroup>
<col  class="org-left">

<col  class="org-left">

<col  class="org-left">

<col  class="org-left">

<col  class="org-left">

<col  class="org-left">

<col  class="org-left">
</colgroup>
<thead>
<tr>
<th scope="col" class="org-left">Name</th>
<th scope="col" class="org-left">Editing is</th>
<th scope="col" class="org-left">Export takes</th>
<th scope="col" class="org-left">Saturation changes</th>
<th scope="col" class="org-left">Contrast changes</th>
<th scope="col" class="org-left">Highlights rescues</th>
<th scope="col" class="org-left">Tonecurve rescues</th>
</tr>

<tr>
<th scope="col" class="org-left">&#xa0;</th>
<th scope="col" class="org-left">&#xa0;</th>
<th scope="col" class="org-left">&#xa0;</th>
<th scope="col" class="org-left">lightness?</th>
<th scope="col" class="org-left">saturation?</th>
<th scope="col" class="org-left">overexposure?</th>
<th scope="col" class="org-left">overexposure?</th>
</tr>
</thead>
<tbody>
<tr>
<td class="org-left">ACDSee Photo Studio</td>
<td class="org-left">realtime</td>
<td class="org-left">25s</td>
<td class="org-left">yes</td>
<td class="org-left">yes</td>
<td class="org-left">yes</td>
<td class="org-left">no</td>
</tr>

<tr>
<td class="org-left">Capture On</td>
<td class="org-left">realtime</td>
<td class="org-left">15s</td>
<td class="org-left">a little</td>
<td class="org-left">no</td>
<td class="org-left">yes</td>
<td class="org-left">no</td>
</tr>

<tr>
<td class="org-left">Darktable</td>
<td class="org-left">delayed</td>
<td class="org-left">15s</td>
<td class="org-left">no</td>
<td class="org-left">no</td>
<td class="org-left">yes</td>
<td class="org-left">yes</td>
</tr>

<tr>
<td class="org-left">DxO PhotoLab</td>
<td class="org-left">delayed</td>
<td class="org-left">45s</td>
<td class="org-left">yes</td>
<td class="org-left">a little</td>
<td class="org-left">yes</td>
<td class="org-left">a little</td>
</tr>

<tr>
<td class="org-left">Lightroom Classic</td>
<td class="org-left">realtime</td>
<td class="org-left">15s</td>
<td class="org-left">a little</td>
<td class="org-left">a little</td>
<td class="org-left">yes</td>
<td class="org-left">a little</td>
</tr>

<tr>
<td class="org-left">ON1 Photo RAW</td>
<td class="org-left">realtime</td>
<td class="org-left">30s</td>
<td class="org-left">yes</td>
<td class="org-left">a little</td>
<td class="org-left">no</td>
<td class="org-left">no</td>
</tr>

<tr>
<td class="org-left">RawTherapee</td>
<td class="org-left">wait and see</td>
<td class="org-left">30s</td>
<td class="org-left">a little</td>
<td class="org-left">yes</td>
<td class="org-left">no</td>
<td class="org-left">no</td>
</tr>

<tr>
<td class="org-left">Silkypix Developer</td>
<td class="org-left">lo-res wait/see</td>
<td class="org-left">80s</td>
<td class="org-left">no</td>
<td class="org-left">a little</td>
<td class="org-left">no</td>
<td class="org-left">no</td>
</tr>

<tr>
<td class="org-left">Exposure X7</td>
<td class="org-left">realtime</td>
<td class="org-left">30s</td>
<td class="org-left">yes</td>
<td class="org-left">strongly</td>
<td class="org-left">yes</td>
<td class="org-left">a little</td>
</tr>

<tr>
<td class="org-left">Zoner Photo Studio</td>
<td class="org-left">lo-res realtime</td>
<td class="org-left">30s</td>
<td class="org-left">yes</td>
<td class="org-left">yes</td>
<td class="org-left">yes</td>
<td class="org-left">a little</td>
</tr>
</tbody>
</table>

<p>
If <i>saturation</i> changes lightness and <i>contrast</i> changes saturation, editing can become rather more difficult, as the effect tends to be hard to counteract without complex luminosity masking. This is a reason for me to dislike my experience with ACDSee, ON1, Exposure, and Zoner particularly. The <i>highlights</i> slider issue also has a big influence on how you edit images. If highlights can be recovered after exposure adjustments, you can use <i>exposure</i> mostly for image brightness, and recover highlights later if needed. On the other hand, if highlights can't be recovered, then the <i>exposure</i> slider must instead be used to protect highlights, and image brightness has to be relegated to the tone curve or shadows/midtones sliders. This feels weirdly backwards to me, and is a reason for me to disregard ON1, RawTherapee, and Silkypix.
</p>

<p>
The gold standard here is of course Darktable, where saturation ("chroma") is completely decoupled from lightness. And, as a particular point of pride, any module whatsoever can edit highlights without any risk of them blowing irretrievably. In practice, this actually simplifies development noticeably. The former is a bit of a double-edged sword, though, as <i>chroma</i> of bright colors can only be pushed so far without going out of gamut; Darktable therefore provides a second <i>saturation</i> control that additionally lowers brightness to keep bright colors in gamut, much like other tools.
</p>

<p>
You may also have noticed that the three examples pictures above were taken with Fujifilm cameras. These cameras are highly acclaimed for their film simulations. Of the tested software, Lightroom Classic, Silkypix Developer, Capture One, and ON1 Photo RAW natively support these film simulations. DxO PhotoLab can add them for an additional €139 <a href="https://www.dxo.com/dxo-filmpack/">FilmPack</a>. And ACDSee Photo Studio, RawTherapee, Darktable, and Exposure X7 at least support third-party LUTs which can retrofit film simulations. Funny how programs <i>either</i> charge money for native film simulations, <i>or</i> support generic LUTs. What a <i>coincidence</i>! (Only ON1 Photo RAW supports both film simulations and (ICC) LUTs, and only Zoner Photo Studio supports neither).
</p>

<p>
So, after spending a few evenings with these programs, what is my verdict?
</p>
</div>

<div id="outline-container-orgb5e532b" class="outline-3">
<h3 id="orgb5e532b">ACDSee Photo Studio Ultimate 2023 ★★★☆☆</h3>
<div class="outline-text-3" id="text-orgb5e532b">
<p>
Overall a rather good package. Fantastic organizational features, too. Even sports an API for extending its functionality! And pixel editing, a mobile app, and just a ton more.
</p>

<p>
However, it does not suit my tastes. Something about the UI and some tools seems a bit unpolished. Particularly, <i>clarity</i> and <i>dehaze</i> produce too strong halos for me, and the denoising is unpleasantly ineffective and smeary. Panning sometimes breaks the image into a pixelated mess, and there's no Fuji film sim support. Still, when it works, it produced some of my favorite renders in this comparison!
</p>

<p>
As another weird point, it's Windows only, and behaves oddly windowsy, too. For example, the library view by default shows all files and folders, not just images, and you actually need to reinstall the entire software if you want to change its language.
</p>
</div>
</div>

<div id="outline-container-org2d5491a" class="outline-3">
<h3 id="org2d5491a">Capture One 22 ★★★★★</h3>
<div class="outline-text-3" id="text-org2d5491a">
<p>
A product I know well, and own a license for. This comparison has reinforced that choice. Capture One's image editing tools are somewhat basic, but they seem refined and flexible. There's a strong focus on workflow efficiency, too, with its <a href="https://learn.captureone.com/tutorials/speed-edit/">speed edit</a> shortcuts and <a href="https://learn.captureone.com/tutorials/style-brushes/">style brushes</a>.
</p>

<p>
If there is a criticism to be leveled at Capture One, it's the high price and the somewhat slow pace of development. Many a competitors' feature is only included in Capture One years after they have become widespread. And many new features focus on the needs of working professional photographer instead of amateurs like me.
</p>

<p>
Regardless, Capture One will remain my one-of-two raw developer of choice. And it runs on my rather slow Surface tablet for emergency vacation edits!
</p>
</div>
</div>

<div id="outline-container-org126402a" class="outline-3">
<h3 id="org126402a">Darktable 4.0 ★★★★☆</h3>
<div class="outline-text-3" id="text-org126402a">
<p>
Darktable is the other raw developer I know intimately. In a sense, it is the polar opposite of Capture One: all the algorithms, parameters, and details are laid bare; nothing is hidden or automated. Its editing tools are also by far the most unusual of this bunch, which must no doubt be bewildering to newcomers. But if you're interested in deep control and alternative editing workflows, there's just nothing like it. Personally, I have <a href="https://github.com/bastibe/Fujifilm-Auto-Settings-for-Darktable">scripted it</a> and <a href="https://bastibe.de/2022-05-04-customizing-darktable-for-fujifilm-cameras.html">molded it</a> extensively, which has made my Darktable similarly efficient and fast as Capture One. Such flexibility is actually rather rare in image editing software.
</p>

<p>
But I seriously hope they fix that horrendous highlights rendering of filmic v6 in the next revision. That's currently a constant pain point to work around.
</p>

<p>
Darktable will remain my one-of-two raw developer of choice. And it runs on Linux!
</p>
</div>
</div>

<div id="outline-container-org7d20733" class="outline-3">
<h3 id="org7d20733">DxO PhotoLab 6 ★★★★☆</h3>
<div class="outline-text-3" id="text-org7d20733">
<p>
This program really is what prompted this entire ordeal. I heard so many good things about DxO PhotoLab, and was planning on replacing Capture One with it after this comparison.
</p>

<p>
There truly is a lot to like about DxO PhotoLab. Its tools seem robust, its default rendering is often very close to a finished image, and its denoising is rather remarkable. However, the program just felt clunky to use. Things are organized inefficiently, some operations take annoyingly long to process, and some effects are only visible in a tiny preview window or indeed the exported file. The local adjustments also seemed unnecessarily cumbersome to use, with that weird radial menu and those awkwardly imprecise "Control Points".
</p>

<p>
And what's with the weirdly branded sliders all over the program? Why is it "DxO Smart Lighting" instead of shadows, "DxO ClearView Plus" instead of dehaze, and "Microcontrast" instead of clarity, and "DxO DeepPrime XD" instead of denoising?
</p>

<p>
Truthfully, I might still have bought a license for this program as it is powerful and fun to use, despite my complaints. But €220 for the main program <i>plus</i> €140 for the FilmPack (for Fujifilm film simulations, but also basics such as a vignette tool) <i>plus</i> €100 for ViewPoint (for cool distortion stuff, but also the keystone tool) is just a bit too much, thank you very much.
</p>
</div>
</div>

<div id="outline-container-org4ae4007" class="outline-3">
<h3 id="org4ae4007">Lightroom Classic 11.5 ★★★★☆</h3>
<div class="outline-text-3" id="text-org4ae4007">
<p>
People like this program, and for good reason. Robust tools, a pleasant rendering, and just a staggering amount of tutorials and help online due to its popularity.
</p>

<p>
Nevertheless, Lightroom does not appeal to me. I don't like how Lightroom seems to takes undue possession of my images on import, I am repelled by the weird old-fashioned UI with its bonkers conventions (hold Alt to show masks, crop moves image instead of rectangle, etc.). I don't like its yearly-subscription-only pricing structure, either, although the price and terms are actually rather reasonable. And I don't like that Adobe Creative Cloud mothership that's necessary to install and maintain Lightroom.
</p>

<p>
But I do realize that this is actually good software. It's just not my favorite.
</p>
</div>
</div>

<div id="outline-container-orgd9d3aeb" class="outline-3">
<h3 id="orgd9d3aeb">ON1 Photo RAW 2023 ★★☆☆☆</h3>
<div class="outline-text-3" id="text-orgd9d3aeb">
<p>
The new AI denoising and sharpening produced only artifacts, the new AI masking completely missed my subjects, there were algorithm artifacts everywhere, such as halos, hue shifts, and clipping. Perhaps something about my version was broken, being a very recent release. Additionally, one time I wanted to do a 1:2 crop, which you have to create a new crop preset for. However, the preset will not be saved with a ":" in the name. It took me a few tries to figure out that that's what prevented me from cropping. It doesn't help that the UI is surprisingly slow, often taking a second or so to redraw a tool change. And the installer is 2.7 GB, three times the size of any other tool in this list!
</p>

<p>
On the other hand, there are some cool tools in the effects panel, and some renders actually didn't look half bad. Perhaps it just needs a few bugfixes or more polish. But as it stands, I can not recommend this software.
</p>
</div>
</div>

<div id="outline-container-org697b4d4" class="outline-3">
<h3 id="org697b4d4">RawTherapee 5.8 ★★★☆☆</h3>
<div class="outline-text-3" id="text-org697b4d4">
<p>
I suppose RawTherapee should be regarded like Darktable, a killer program that requires deep study to wield well. I did not wield it well, but that probably says more about me than RawTherapee.
</p>

<p>
Still, I don't like the somewhat busy program layout, and how some operations take a long time to process. The export workflow is also strangely unusual, but I'm sure that that's something I could get used to. And I hear the next version will come with local adjustments.
</p>

<p>
Perhaps it is better-suited for a detail-oriented user than me. There's a lot to like here, but it's not what I'm looking for.
</p>
</div>
</div>

<div id="outline-container-org6146a00" class="outline-3">
<h3 id="org6146a00">Silkypix Developer Studio Pro 11 ★☆☆☆☆</h3>
<div class="outline-text-3" id="text-org6146a00">
<p>
Something about this program is endearing to me. But in this comparison, it was just more cumbersome than useful. Many of its tools simply were not up to the task (can't raise shadows far enough, denoising produces only artifacts). And at some point, it slowed down to the point where it would take several seconds to see the effects of a single slider movement. This program did not work for me.
</p>
</div>
</div>

<div id="outline-container-org37ee909" class="outline-3">
<h3 id="org37ee909">Exposure X7 ★★☆☆☆</h3>
<div class="outline-text-3" id="text-org37ee909">
<p>
Another strangely unpolished program on this list. Somehow, fonts everywhere are huge for no apparent reason, and sliders uncomfortably short. And I struggled preventing it from blowing highlights and clipping shadows. I don't see the appeal of this program.
</p>
</div>
</div>

<div id="outline-container-orgb288206" class="outline-3">
<h3 id="orgb288206">Zoner Photo Studio X Fall 2022 ★★★★☆</h3>
<div class="outline-text-3" id="text-orgb288206">
<p>
As of the most recent version, Zoner Photo finally added native support for some Fujifilm cameras. Not all of my cameras are included yet, but to their credit, Zoner Photo can still open the missing files through ACR, albeit a bit more slowly.
</p>

<p>
Really, there is a lot to like about this program. Most tools work as advertised, with few issues (no local white balance, somewhat ineffective denoising), and a strong automatic mode. I also enjoy how it is unapologetically Windows-only, and uniquely feels <i>native</i> to Windows in a pleasant way.
</p>

<p>
It's a somewhat basic program compared to some of these others, but it's appropriately affordable, and fast. Not exactly what I'm looking for, but highly recommended for what it is!</p>
</div>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2022-10-12-raw-developer-comparison.html</link>
  <guid>https://bastibe.de/2022-10-12-raw-developer-comparison.html</guid>
  <pubDate>Tue, 11 Oct 2022 19:15:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Darktable for Fujifilm Cameras]]></title>
  <description><![CDATA[
<p>
You know what I like to see when I import photos from my Fujifilm camera into Darktable?
</p>

<figure>
<img src="/static/2022-05/darktable-fuji.png" alt="A screenshot of darktable, with RAF files, autocropped, auto-DR'd, with film simulation applied"/>
<figcaption>Each RAF file has tags with the aspect ratio, DR mode, and film simulation, is exposed correctly, cropped correctly, and has the correct film simulation applied.</figcaption>
</figure>

<p>
However, that is not the default. Darktable, like most raw developers, is camera-agnostic.
</p>

<div style="margin-left: 2em">
<h3>agnostic</h3>
ăg-nŏs′tĭk <br>
<b>noun</b> </br>
[...] <br>
<ol start="3">
<li>One who is doubtful or noncommittal about something.</li>
</ol>
</div>

<p>
Which means that Darktable does not know about any Fujifilm-specific raw file metadata, such as crop, dynamic range modes, or film simulations. Thus what you'd normally see in Darktable is more like this:
</p>

<figure>
<img src="/static/2022-05/darktable-default.png" alt="A screenshot of default darktable, DR200/DR400 files are underexposed, no crops are applied, default rendering, no tags."/>
<figcaption>Default darktable, DR200/DR400 files are underexposed, no crops are applied, colors don't quite match, no tags.</figcaption>
</figure>

<p>
Notice how all the DR200/DR400 images are underexposed by one and two stops, how the first JPG is a square crop, but the RAF is 3:2, how the color of the grass and the train are subtly different in RAF and JPG.
</p>

<p>
But thankfully, Darktable has a scripting interface for automating things. And what I've done here is a little script that uses <a href="https://www.exiftool.org/">exiftool</a> to read the missing metadata from the RAF file and apply appropriate styles to get Darktable's default rendering close to the JPG.
</p>

<p>
Here's the lua script in its entirety:
</p>


<div style="height: 20em; overflow: scroll; background-color: #eee; padding-left: 1em">

<p>
<a href="https://bastibe.de/static/2022-05/fujifilm_auto_settings.lua">fujifilm ̲auto ̲settings.lua</a>
</p>

<div class="org-src-container">
<pre class="src src-lua">--[[ fujifilm_auto_settings-0.2

Apply Fujifilm film simulations, in-camera crop mode, and dynamic range.

Copyright (C) 2022 Bastian Bechtold &lt;bastibe.dev@mailbox.org&gt;

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--]]

--[[About this Plugin
Automatically applies styles that load Fujifilm film simulation LUTs,
copy crop ratios from the JPG, and correct exposure according to the
chosen dynamic range setting in camera.

Dependencies:
- exiftool (https://www.sno.phy.queensu.ca/~phil/exiftool/)
- Fuji LUTs (https://blog.sowerby.me/fuji-film-simulation-profiles/)

Based on fujifim_dynamic_range by Dan Torop.

  Film Simulations
  ----------------

Fujifilm cameras are famous for their film simulations, such as Provia
or Velvia or Classic Chrome. Indeed it is my experience that they rely
on these film simulations for accurate colors.

Darktable however does not know about or implement these film
simulations. But they are available to download from Stuart Sowerby as
3DL LUTs. (PNG LUTs are also available, but they show a strange
posterization artifact when loaded in Darktable, which the 3DLs do
not).

In order to use this plugin, you must prepare a number of styles:
- provia
- astia
- velvia
- classic_chrome
- pro_neg_standard
- pro_neg_high
- eterna
- acros_green
- acros_red
- acros_yellow
- acros
- mono_green
- mono_red
- mono_yellow
- mono
- sepia

These styles should apply the according film simulation in a method of
your choosing.

This plugin checks the image's "Film Mode" exif parameter, and applies
the appropriate style. If no matching style exists, no action is taken
and no harm is done.

  Crop Factor
  -----------

Fujifilm cameras allow in-camera cropping to one of three aspect
ratios: 2:3 (default), 16:9, and 1:1.

This plugin checks the image's "Raw Image Aspect Ratio" exif
parameter, and applies the appropriate style.

To use, prepare another four styles:
- square_crop_portrait
- square_crop_landscape
- sixteen_by_nine_crop_portrait
- sixteen_by_nine_crop_landscape

These styles should apply a square crop and a 16:9 crop to
portrait/landscape images. If no matching style exists, no action is
taken and no harm is done.

  Dynamic Range
  -------------

Fujifilm cameras have a built-in dynamic range compensation, which
(optionally automatically) reduce exposure by one or two stops, and
compensate by raising the tone curve by one or two stops. These modes
are called DR200 and DR400, respectively.

The plugin reads the raw file's "Auto Dynamic Range" or "Development
Dynamic Range" parameter, and applies one of two styles:
- DR200
- DR400

These styles should raise exposure by one and two stops, respectively,
and expand highlight latitude to make room for additional highlights.
I like to implement them with the tone equalizer in eigf mode, raising
exposure by one/two stops over the lower half of the sliders, then
ramping to zero at 0 EV. If no matching styles exist, no action is
taken and no harm is done.

These tags have been checked on a Fujifilm X-T3 and X-Pro2. Other
cameras may behave in other ways.

--]]

local dt = require "darktable"
local du = require "lib/dtutils"
local df = require "lib/dtutils.file"

du.check_min_api_version("7.0.0", "fujifilm_auto_settings")

-- return data structure for script_manager

local script_data = {}

script_data.destroy = nil -- function to destory the script
script_data.destroy_method = nil -- set to hide for libs since we can't destroy them completely yet, otherwise leave as nil
script_data.restart = nil -- how to restart the (lib) script after it's been hidden - i.e. make it visible again

local function exiftool_get(exiftool_command, RAF_filename, flag)
    local command = exiftool_command .. " " .. flag .. " -t " .. RAF_filename
    dt.print_log(command)
    local output = io.popen(command)
    local exiftool_result = output:read("*all")
    output:close()
    if #exiftool_result == 0 then
        dt.print_error("[fujifilm_auto_settings] no output returned by exiftool")
        return
    end
    local exiftool_result = string.match(exiftool_result, "\t(.*)")
    if not exiftool_result then
        dt.print_error("[fujifilm_auto_settings] could not parse exiftool output")
        return
    end
    exiftool_result = exiftool_result:match("^%s*(.-)%s*$") -- strip whitespace
    return exiftool_result
end

local function apply_style(image, style_name)
    for _, s in ipairs(dt.styles) do
        if s.name == style_name then
            dt.styles.apply(s, image)
            return
        end
    end
    dt.print_error("[fujifilm_auto_settings] could not find style " .. style_name)
end

local function apply_tag(image, tag_name)
    local tagnum = dt.tags.find(tag_name)
    if tagnum == nil then
        -- create tag if it doesn't exist
        tagnum = dt.tags.create(tag_name)
        dt.print_log("[fujifilm_auto_settings] creating tag " .. tag_name)
    end
    dt.tags.attach(tagnum, image)
end


local function detect_auto_settings(event, image)
    if image.exif_maker ~= "FUJIFILM" then
        dt.print_log("[fujifilm_auto_settings] ignoring non-Fujifilm image")
        return
    end
    -- it would be nice to check image.is_raw but this appears to not yet be set
    if not string.match(image.filename, "%.RAF$") then
        dt.print_log("[fujifilm_auto_settings] ignoring non-raw image")
        return
    end
    local exiftool_command = df.check_if_bin_exists("exiftool")
    if not exiftool_command then
        dt.print_error("[fujifilm_auto_settings] exiftool not found")
        return
    end
    local RAF_filename = df.sanitize_filename(tostring(image))

    -- dynamic range mode
    -- if in DR Auto, the value is saved to Auto Dynamic Range, with a % suffix:
    local auto_dynamic_range = exiftool_get(exiftool_command, RAF_filename, "-AutoDynamicRange")
    -- if manually chosen DR, the value is saved to Development Dynamic Range:
    if auto_dynamic_range == nil then
        auto_dynamic_range = exiftool_get(exiftool_command, RAF_filename, "-DevelopmentDynamicRange") .. '%'
    end
    if auto_dynamic_range == "100%" then
        apply_tag(image, "DR100")
        -- default; no need to change style
    elseif auto_dynamic_range == "200%" then
        apply_style(image, "DR200")
        apply_tag(image, "DR200")
        dt.print_log("[fujifilm_auto_settings] DR200")
    elseif auto_dynamic_range == "400%" then
        apply_style(image, "DR400")
        apply_tag(image, "DR400")
        dt.print_log("[fujifilm_auto_settings] DR400")
    end

    -- cropmode
    local raw_aspect_ratio = exiftool_get(exiftool_command, RAF_filename, "-RawImageAspectRatio")
    if raw_aspect_ratio == "3:2" then
        apply_tag(image, "3:2")
        -- default; no need to apply style
    elseif raw_aspect_ratio == "1:1" then
        if image.width &gt; image.height then
            apply_style(image, "square_crop_landscape")
        else
            apply_style(image, "square_crop_portrait")
        end
        apply_tag(image, "1:1")
        dt.print_log("[fujifilm_auto_settings] square crop")
    elseif raw_aspect_ratio == "16:9" then
        if image.width &gt; image.height then
            apply_style(image, "sixteen_by_nine_crop_landscape")
        else
            apply_style(image, "sixteen_by_nine_crop_portrait")
        end
        apply_tag(image, "16:9")
        dt.print_log("[fujifilm_auto_settings] 16:9 crop")
    end

    -- filmmode
    local raw_filmmode = exiftool_get(exiftool_command, RAF_filename, "-FilmMode")
    local style_map = {
        ["Provia"] = "provia",
        ["Astia"] = "astia",
        ["Classic Chrome"] = "classic_chrome",
        ["Eterna"] = "eterna",
        ["Acros+G"] = "acros_green",
        ["Acros+R"] = "acros_red",
        ["Acros+Ye"] = "acros_yellow",
        ["Acros"] = "acros",
        ["Mono+G"] = "mono_green",
        ["Mono+R"] = "mono_red",
        ["Mono+Ye"] = "mono_yellow",
        ["Mono"] = "mono",
        ["Pro Neg Hi"] = "pro_neg_high",
        ["Pro Neg Std"] = "pro_neg_standard",
        ["Sepia"] = "sepia",
        ["Velvia"] = "velvia",
    }
    for key, value in pairs(style_map) do
        if string.find(raw_filmmode, key) then
            apply_style(image, value)
            apply_tag(image, key)
            dt.print_log("[fujifilm_auto_settings] film simulation " .. key)
        end
    end
end

local function detect_auto_settings_multi(event, shortcut)
    local images = dt.gui.selection()
    if #images == 0 then
        dt.print(_("Please select an image"))
    else
        for _, image in ipairs(images) do
            detect_auto_settings(event, image)
        end
    end
end

local function destroy()
    dt.destroy_event("fujifilm_auto_settings", "post-import-image")
    dt.destroy_event("fujifilm_auto_settings", "shortcut")
end

if not df.check_if_bin_exists("exiftool") then
    dt.print_log("Please install exiftool to use fujifilm_auto_settings")
    error "[fujifilm_auto_settings] exiftool not found"
end

dt.register_event("fujifilm_auto_settings", "post-import-image", detect_auto_settings)

dt.register_event("fujifilm_auto_settings", "shortcut", detect_auto_settings_multi, "fujifilm_auto_settings")

dt.print_log("[fujifilm_auto_settings] loaded")

script_data.destroy = destroy

return script_data
</pre>
</div>

</div>

<p>
However, there's a catch: Scripts in Darktable can not modify darkroom state directly. But they <i>can</i> load styles. So to make the script work, we need to define a number of styles that do the heavy lifting here:
</p>

<ul class="org-ul">
<li>Two styles <code>DR200</code> and <code>DR400</code> for the dynamic range modes that brighten the image by one and two stops, respectively (I like to use the Tone Equalizer <a href="https://bastibe.de/static/2022-05/DR200.png">like this</a>).</li>
<li>Four styles <code>square ̲crop_landscape</code> and <code>square ̲crop_portrait</code> and <code>sixteen ̲by ̲nine ̲crop_landscape</code> and <code>sixteen ̲by ̲nine ̲crop_portrait</code> that crop landscape/portrait images to 1:1 and 16:9 ratio.</li>
<li>One style for each film simulation you use: <code>provia</code>, <code>astia</code>, <code>velvia</code>, <code>classic ̲chrome</code>, <code>pro ̲neg ̲standard</code>, <code>pro ̲neg ̲high</code>, <code>eterna</code>, <code>acros</code>, <code>acros ̲green</code>, <code>acros ̲red</code>, <code>acros ̲yellow</code>, <code>mono</code>, <code>mono ̲green</code>, <code>mono ̲red</code>, <code>mono ̲yellow</code>, <code>sepia</code>.
The linked styles use <a href="https://blog.sowerby.me/fuji-film-simulation-profiles/">Stuart Sowerby's Film Simulation LUTs</a> as film simulations, which must be installed in <code>$LUTs/Fujifilm XTrans III/$lut.3dl</code>.</li>
</ul>

<p>
Download a zip file with all the above styles <a href="https://bastibe.de/static/2022-05/styles.zip">here</a>, and appropriately-renamed LUTs <a href="https://bastibe.de/static/2022-05/Fujifilm%20XTrans%20III.zip">here</a>. (This section will be revised once I finish building my own set of LUTs).
</p>

<p>
Then copy the lua script to <code>~/.config/darktable/lua/contrib/</code>, activate it in the script manager (bottom left in the lighttable), and it should automatically run whenever you import new Fujifilm raf files! (Start Darktable with <code>darktable -d opencl</code> to see debug messages, and bind a keyboard shortcut to <code>lua scripts/fujifilm_auto_settings</code> to trigger the script manually.)
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> <a href="https://bastibe.de/tag-fujifilm.html">fujifilm</a> <a href="https://bastibe.de/tag-darktable.html">darktable</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <category><![CDATA[fujifilm]]></category>
  <category><![CDATA[darktable]]></category>
  <link>https://bastibe.de/2022-05-04-customizing-darktable-for-fujifilm-cameras.html</link>
  <guid>https://bastibe.de/2022-05-04-customizing-darktable-for-fujifilm-cameras.html</guid>
  <pubDate>Wed, 04 May 2022 20:41:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Converting Capture one Presets to LUTs]]></title>
  <description><![CDATA[
<p>
A while ago, I bought an <a href="https://www.reallyniceimages.com/">RNI film pack</a> for Capture One. That's a set of presets that makes your digital photos look similar to analog film scans. However, since then my <i>other</i> image editor, <a href="https://www.darktable.org/">Darktable</a> just released a new version, I'm now back to using Darktable instead of Capture One, thus without access to those presets.
</p>

<p>
Here's how to export Capture One presets to LUTs, to make them accessable to other programs.
</p>

<p>
The fun thing is, LUTs are just PNG files that contain a table of colors. You know, a "Look Up Table", of sorts. So, in order convert a preset to a LUT, all we need to do is apply the preset to a pristine "identity" LUT, and export it as a new PNG.
</p>

<ol class="org-ol">
<li>Get yourself an identity LUT. <br>
For example, the one included in <a href="https://blog.sowerby.me/fuji-film-simulation-profiles/">Stuart Sowerby's Fuji Film Simulation Profiles</a>. Choose the sRGB PNG LUTs, for RawTherapee and Affinity Photo.</li>
<li>Open the LUT PNG in Capture One.</li>
<li>Apply the preset you want. <br>
Optionally lower <i>saturation</i> by -15, see below.</li>
<li>Export as PNG. <br>
Make sure the color space is sRGB, just like the original file.</li>
</ol>

<p>
As easy as that.
</p>

<p>
A few more adjustments: many Capture One presets expect to be working on raw data, which is less saturated than Darktable's default. So I export with -15 <i>saturation</i>. Also, many presets include spacial adjustments such as Highlights or Shadows that are bound to not play well with the LUT PNG. To disable them, delete the offending lines from the *.costyle files<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>, or compensate the values with opposite slider movements.
</p>

<p>
When applying the LUTs in Darktable's <i>lut 3D</i> module, there are a few more things you can do to fit them into your workflow. For example, you can lower the opacity of the <i>lut 3D</i> module to vary their effect. Or you can choose <i>chromaticity</i> as blend more to only apply their color transformation, but keep Darktable's tonal rendering. In <i>normal</i> blend mode, some LUTs prefer a flat rendering as their input, so lower <i>contrast</i> in <i>filmic rgb</i> to zero and use the auto-pickers to set the image black and white point.
</p>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">don't do this for RNI LUTs, it's forbidden by the User License Agreement that is hidden quite well in dark-grey-on-black at the very bottom of their website</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2022-01-09-converting-capture-one-presets-to-luts.html</link>
  <guid>https://bastibe.de/2022-01-09-converting-capture-one-presets-to-luts.html</guid>
  <pubDate>Sun, 09 Jan 2022 14:37:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Books of 2021]]></title>
  <description><![CDATA[

<div id="outline-container-org654eb72" class="outline-2">
<h2 id="org654eb72">Hologrammatica</h2>
<div class="outline-text-2" id="text-org654eb72">
<figure style="float:left">
<img src="/static/2022-01/hologrammatica cover.jpg" alt="book cover for Hologrammatica" width="150px"/>
</figure>

<p>
In the last years, I have almost exclusively read books in English. Science fiction, in particular, seems to happen exclusively in English (and perhaps <a href="https://www.goodreads.com/series/189931-remembrance-of-earth-s-past">Chinese</a>). So much so, that I have come to associate German only with bad translations and personal communications, whereas English was the language of science, engineering, and fiction. In 2021 however, to my surprise, I stumbled upon Tom Hillenbrand's <i>Hologrammatica</i>, an science fiction thriller in German. It was a peculiar experience, reading the familiar tropes of the genre in a different language. Somehow it made the story feel more immediate and approachable to me. Strange, what effect language can have.
</p>

<p>
In the book, humanity has decided to hide reality behind holograms. Clothes and hairstyles can be altered on the fly, street lighting is replaced with projected advertisements. The twist is that in this semi-dystopian world, everyone knows that the holograms hide the truth, which is a collapsed society and dilapidated infrastructure. It is a smart, very current backdrop for a detective story with mind uploads, space elevators, and all the modern trappings of science fiction. A thoroughly enjoyable read!
</p>

<p>
Sci-Fi honorable mentions: Andy Weir's pop sci-fi <i>Project Hail Mary</i> and Martha Well's first novel-length murderbot entry <i>Fugitive Telemetry</i>.
</p>
</div>
</div>

<div id="outline-container-org1461111" class="outline-2">
<h2 id="org1461111">Not Much of an Engineer</h2>
<div class="outline-text-2" id="text-org1461111">
<figure style="float:left">
<img src="/static/2022-01/not much of an engineer cover.jpg" alt="book cover for Not Much of an Engineer" width="150px"/>
</figure>

<p>
I have always been fascinated with aviation, and the technology of warfare. But most of the non-fiction I have read about these topics focuses on the stories of pilots and companies and soldiers, not engineers. In these stories some of the most important plot points came from advances in technology, yet they didn't describe how those changes came about. In 2021, I finally found a good history of aviation technology: Sir Stanley Hooker's <i>Not Much of an Engineer</i> describes the work of the author as the principal engineer at Bristol and Rolls-Royce from the Merlin-era second world war engines to modern turbofans. I guess you need to be a bit of an aviation/engineering geek to enjoy this, but to me this book was an important missing link that I had always looked for.
</p>

<p>
Non-fiction honorable mentions: David Goodsell's <i>The Machinery of Life</i> wonderfully illustrates the inner workings of cells.
</p>
</div>
</div>

<div id="outline-container-orgd1d88aa" class="outline-2">
<h2 id="orgd1d88aa">Crafting Interpreters</h2>
<div class="outline-text-2" id="text-orgd1d88aa">
<figure style="float:left">
<img src="/static/2022-01/crafting interpreters cover.jpg" alt="book cover for Crafting Interpreters" width="150px"/>
</figure>

<p>
How do computers work? This question is surprisingly hard to answer. For me, the answer came in three books: Charles Petzold's <i>Code: The Hidden Language of Computer Hardware and Software</i> explained to me how processors work. The Arpaci-Dusseau's <a href="https://pages.cs.wisc.edu/~remzi/OSTEP/"><i>Operating Systems: Three Easy Pieces</i></a> describes the infrastructure of operating systems that make processors and storage and network available to programs. And now, finally, Robert Nystrom's <a href="https://craftinginterpreters.com/"><i>Crafting Interpreters</i></a> filled in the last step, how a programming language is built.
</p>

<p>
The book describes two implementations of a simple programming language. The first one is a high-level introductory scripting language implemented in Java, the second a high-performance reimplementation in C. Fascinatingly, the entire source code for these implementations is included in the book's text, such that you can entirely follow along (or program along) and have a working programming language at all times. A truly eye-opening glimpse into the innards of the tools we are using every day. The book requires familiarity with Java and C to enjoy.
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-books.html">books</a> ]]></description>
  <category><![CDATA[books]]></category>
  <link>https://bastibe.de/2022-01-04-books-of-2021.html</link>
  <guid>https://bastibe.de/2022-01-04-books-of-2021.html</guid>
  <pubDate>Tue, 04 Jan 2022 09:40:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Fixing AMD OpenCL on Windows]]></title>
  <description><![CDATA[
<p>
When I recently installed Windows 11 on my desktop, my photo editor Darktable suddenly got much slower than it used to be. When I looked into its preferences, I noticed OpenCL was no longer available.
</p>

<p>
As it turns out, some versions of the AMD graphics driver apparently no longer ship with OpenCL support on Windows. However, they <i>do</i> ship with the necessary libraries, it's just that these libraries are not registered any longer.
</p>

<p>
To register them, open the Registry Editor (aka <i>regedit.exe</i>), navigate to the key <code>HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\OpenCL\Vendors</code> (if the key does not exist, create it), and create a new DWORD of Value <code>0</code>. Now rename the DWORD to be the path to your <i>amdocl64.dll</i>. Mine is <code>C:\Windows\System32\DriverStore\FileRepository\u0344717.inf_amd64_d38cec78c83eee99\B343886\amdocl64.dll</code>. Search <i>C:\Windows\System32\</i> for <i>amdocl64.dll</i> to find the correct path on your computer.
</p>

<p>
With that, OpenCL was once again recognized by Darktable and the rest of my photo editing programs.
</p>

<p>
(<a href="https://github.com/ethereum-mining/ethminer/issues/2001#issuecomment-662288143">source</a>)
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-computers.html">computers</a> <a href="https://bastibe.de/tag-windows.html">windows</a> ]]></description>
  <category><![CDATA[computers]]></category>
  <category><![CDATA[windows]]></category>
  <link>https://bastibe.de/2021-12-04-fixing-amd-opencl-on-windows.html</link>
  <guid>https://bastibe.de/2021-12-04-fixing-amd-opencl-on-windows.html</guid>
  <pubDate>Sat, 04 Dec 2021 09:19:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Comparing the Fujifilm XF 16‑80 with the XF 18‑135 Travel Zoom Lenses]]></title>
  <description><![CDATA[
<p>
When I bought into the Fuji system, <a href="https://bastibe.de/2019-05-11-fuji-zoom-lenses.html">I selected the XF 18‑135 f/3.5‑5.6 R LM OIS WR</a> as my main zoom lens. This is a lens with a very wide focal range, that is commonly called a “travel zoom” because you could travel the world with just this one lens. And indeed <a href="https://bastibe.de/2019-10-27-travel-cameras.html">I happily did</a>. In 2019, Fujifilm released a <i>second</i> travel zoom lens, the XF 16‑80 f/4 R OIS WR. Ever since, I have wondered how this new 16‑80 compares to my 18‑135. But given that these lenses are somewhat similar, few people on the internet were ever able to compare them side by side. This blog post will change that.
</p>

<p>
The 18‑135 has served me very well indeed. Of course it is not the world's brightest lens, nor sharpest, nor smallest. But so long as I can get the shot, these limitations don't bother me. Except for two things: The transition between in-focus and out-of-focus can be a bit rough, and my lens extends on its own when carried on a sling. My hope is that the 16‑80 has a nicer rendering, especially for people photos with out-of-focus backgrounds, and a stiffer zoom ring that doesn't creep.
</p>

<figure>
<img src="/static/2021-10/DSCF6485_4.jpg" alt="Picture of Squirrel, with hazy bokeh"/>
<figcaption>Instead of smoothly blurring, the near-focus areas of the 18‑135 have this strange, hazy look</figcaption>
</figure>

<div id="outline-container-org9fb9380" class="outline-2">
<h2 id="org9fb9380">Physical</h2>
<div class="outline-text-2" id="text-org9fb9380">
<p>
Physically, the 16‑80 is a slight bit smaller (89 mm vs 98 mm) and ligher (440 g vs 490 g) than the 18‑135, but the difference is negligible on camera. If anything, the 16‑80 actually feels a bit <i>bigger</i> to me due to its larger front element. Some people claim that the 16‑80 feels better built than the 18‑135. To that end, the rings on my 16‑80 turn more smoothly than my 18‑135's, but then that is comparing a new-ish lens to a well-used one. Autofocus speeds are also reputably different, but they feel similar to me.
</p>

<p>
The 16‑80 has a numbered aperture ring that allows for adjustments while the camera is turned off. On the other hand, the 18‑135 can switch to and from auto-aperture without losing its preset aperture, which is useful as well. The ideal lens for me would have both the auto-aperture switch <i>and</i> the numbered aperture ring. Oh well.
</p>

<figure>
<img src="/static/2021-10/allthelenses.jpg" alt="A picture of the two lenses from the side, both collapsed and extended"/>
<img src="/static/2021-10/lensfront.jpg" alt="A picture of the two lenses from the front"/>
<figcaption>Size comparison of the two lenses. The 18‑135 is a longer, and the 16‑80 wider. Note the marked aperture ring on the 16‑80, and the Auto-Aperture/OIS switches on the 18‑135.</figcaption>
</figure>

<p>
The 16‑80 has a 72 mm filter thread, while the 18‑135 uses 67 mm filters. This is somewhat annoying for me, as my filters are all 67 mm, which also fit on my 70‑300. I'd imagine users of the 72 mm 10‑24 see this differently. Anyway, using a thin polarizer with a 72‑to‑67 step-down ring works without issue on the 16‑80. My inch-thick macro filter however does vignette heavily until 23 mm.
</p>
</div>
</div>

<div id="outline-container-orga8c3657" class="outline-2">
<h2 id="orga8c3657">Rendering</h2>
<div class="outline-text-2" id="text-orga8c3657">
<p>
In terms of rendering, I find the 16‑80 to have a gentler transition from in-focus to out-of-focus, and indeed render out-of-focus backgrounds more smoothly than the 18‑135. At the long end, the 16-80 is actually a useful portrait lens, which is an unexpected but welcome feature for my photography.
</p>

<figure>
<img src="/static/2021-10/bokeh.jpg" alt="A picture taken with each lens, with a blurry background"/>
<figcaption>Rendering of out-of-focus elements. Especially the points of light in the top right have an asymmetric crescent shape for the 18‑135, but blur smoothly for the 16‑80.</figcaption>
</figure>

<p>
At the wide end, the 16‑80 exhibits some significant distortion. While the camera or post processing programs can easily correct this, it leaves the image corners stretched, and renders the 16‑80's nice round bokeh balls as ugly ovals. Thus large-aperture shots at the wide end can be somewhat problematic.
</p>
</div>
</div>

<div id="outline-container-org13aa030" class="outline-2">
<h2 id="org13aa030">Resolution</h2>
<div class="outline-text-2" id="text-org13aa030">
<p>
Next, let's compare the resolution of the two lenses. To do that, I printed a <a href="https://www.graphics.cornell.edu/~westin/misc/res-chart.html">test chart</a>, and took some test images. All images were taken in identical illumination, on a tripod, with the chart covering half the sensor height/width. The following graphic shows a resolution scale near the center of the frame and near the left edge of the frame. And just for fun, I've thrown in a similar analysis from two prime lenses as well. The resolution scales are in 200x line widths per picture height. On my 6000×4000-pixel sensor, the theoretical maximum resolution would therefore be a resolution number of ⁴⁰⁰⁰∕₂₀₀ = 20. All test images are straight crops from original images, reproduced at their original resolution.
</p>

<figure>
<img src="/static/2021-10/comparison.svg" alt="A grid of crops of a test chart, with various lenses at various focal lengths and f‑numbers" width="4724px", height="4960px"/>
<figcaption>Comparison of lens resolution with a test chart. Each image is a direct crop at the X‑T2's native resolution. Resolution numbers in 200x line widths per image height.</figcaption>
</figure>

<p>
Center images were focused in the center, and side images were focused on the side. A two-second timer was used to eliminate camera shake. Due to the geometry of my room and the size of my printer, all pictures were taken near the close-focusing distance of the lenses. A red line indicates the limit of resolution of these lines, as judged by my eyes. The corresponding resolution numbers are generally consistent with the ones published by <a href="https://opticallimits.com/fuji_x/1103_fuji1680f4ois">opticallimits</a> and <a href="https://www.lenstip.com/571.4-Lens_review-Fujifilm_Fujinon_XF_16-80_mm_f_4_R_OIS_WR_Image_resolution.html">lenstip</a><sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>, albeit I judged them a bit more conservatively.
</p>

<p>
The results of this test are surprising to me: the 16‑80 is actually my sharpest lens. It not only bests the 18‑135 at all settings, but also the 35 f/1.4. Only the 60 f/2.4 can reach similar resolution at the same f‑numbers. Generally, the 16‑80 is perfectly sharp right from f/4, while the 18‑135 has to be stopped down to f/8 to reach a similar resolution, especially on the image edges. Only at the long end does the 16‑80 benefit from stopping down.
</p>

<p>
That said, take these resolution measurements with a grain of salt. For instance, a “great” result of 15 (3000 LW/PH) translates to a blur radius of 1.3 pixels, while a “mediocre” result of 10 (2000 LW/PH) is instead 2 pixels. This is scientifically significant, but not at all relevant to (my) photography.
</p>

<p>
Additionally, the fact that the 60 f/2.4 macro lens scores so highly but the 35 f/1.4 does not is an indication that these measurements might be biased by being taken near the close focusing distance of the lenses. Thus the next set of images compares these lenses at more natural distances.
</p>

<figure>
<img src="/static/2021-10/resolution.jpg" alt="A grid of crops from a landscape shot, with the two lenses at various focal lenths and f‑numbers"/>
<figcaption>Comparison of lens resolution with natural images. Each image is a 500x500 pixel crop from original photographs. The subject is ca. 100 m from the camera.</figcaption>
</figure>

<p>
At this farther distance, and with a more natural subject, the differences are no longer as easily visible. What differences there are this time favor the 18‑135 instead of the 16‑80. Interestingly, I didn't see any significant differences between these pictures when looking at them “merely” side-by-side in Capture One. Only when I actually assembled these here graphics and looked at them at 200% did the differences become apparant.
</p>

<p>
Nevertheless, it remains curious that there would be such a difference between the two lenses. Then, someone mentioned that the 16‑80 might suffer from <i>shutter shock</i>, where the camera's mechanical shutter jolts the camera enough to upset the image stabilization system and induce a slight bit of motion blur. An issue such as this might explain the 16‑80's slightly reduced resolution in my test shots. So I created another series of images, but this time both, with the mechanical shutter, and with electronic shutter. In electronic shutter mode, nothing moves in the camera and there can be no shutter shock.
</p>

<figure>
<img src="/static/2021-10/shutter.jpg" alt="A grid of crops from a landscape shot, with the two lenses at various focal lenths and f‑numbers and with electronic and mechanical shutter"/>
<figcaption>Comparison of lens resolution and shutter shock. Each image is a 500x500 pixel crop from original images. The subject is ca. 100 m from the camera.</figcaption>
</figure>

<p>
From this comparison, I can see no evidence of shutter shock. It might have been an issue on earlier firmware versions of the 16‑80, but my camera (an X-T2) and lens (at firmware 1.05) does not does not exhibit shutter shock. Furthermore, this series of pictures shows the 16‑80 and 18‑135 essentially matched in image resolution.
</p>

<p>
All of that said, I must add that all of these comparisons used extremely tight crops of high-contrast geometrical features. Most of the differences here are all but invisible in actual photographs. From these resolution experiments, I see no reason to prefer one lens over the other. Both of them are perfectly sharp in everyday use.
</p>
</div>
</div>

<div id="outline-container-orge73d9db" class="outline-2">
<h2 id="orge73d9db">Conclusion</h2>
<div class="outline-text-2" id="text-orge73d9db">
<p>
So, how to choose between the Fujifilm XF 16‑80 f/4 R OIS WR and the XF 18‑135 f/3.5‑5.6 R LM OIS WR? My 16‑80 has tighter aperture and zoom rings, does not creep, and has a smoother rendering of out-of-focus background. On the other hand, I do find the increased telephoto of the 18‑135 very useful, and it doesn't suffer from wide-angle distortion as much as the 16‑80.
</p>

<p>
In terms of resolution, I did not find fault with either lens. Both are very sharp across their entire focal range and the entire frame. That said, the 18‑135 does benefit from stopping down for optimum resolution, while the 16‑80 is sharp right from f/4, and the 16‑80 might be sharper for closer subjects.
</p>

<p>
My tentative conclusion from these experiments is therefore that I would slightly prefer the 16‑80 for people pictures, where the close-focus sharpness and nicer background rendering are advantageous, and the larger aperture at 80 mm might make a difference. And I would prefer the 18-135 for landscapes, where stopping down is usually easy and the longer focal length comes in handy.
</p>

<p>
That said, the differences in rendering and resolution are really very minor, and the choice most importantly comes down to the focal range. Which is as it should be with modern lenses. And both lenses are of course very well-built, weather sealed, and have fantastic image stabilization. But you probably knew that already.
</p>
</div>
</div>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">multiply lenstip numbers by 2×16.7 mm to convert from lpmm (lines per millimeter) to LW/PH (line width per picture height)</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2021-10-09-fuji-travel-zooms.html</link>
  <guid>https://bastibe.de/2021-10-09-fuji-travel-zooms.html</guid>
  <pubDate>Sat, 09 Oct 2021 15:16:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[A Review of Darktable]]></title>
  <description><![CDATA[
<p>
With version 3.0, my favorite photo editing software Darktable started the journey towards a scene-referred editing pipeline. Which means that most edits are no longer bounded between a fixed black zero, and a white one, but can range between zero and infinity, like light itself. This is the norm in video editing and video games, but unique in photo editors at the moment. The scene-referred pipeline has brought changes to pretty much all parts of the editing workflow. I have been frustrated with it, too, even opting to use <a href="https://bastibe.de/2021-05-04-a-review-of-the-raw-photo-editor-capture-one.html">Capture One</a> for a while. But with version 3.6, Darktable seems to have found a new stride. This article is about my favorite features in Darktable 3.6, contrasting it with Capture One's more traditional toolset.
</p>

<p>
A camera sensor records light. When there is very little light, we call that "black", but there is really no similar label for when there is a lot of it. It's just very bright. A very bright blue light is still blue, and could always be brighter. However, screens and print and analog film can not get arbitrarily bright. Instead, they have a limited maximum brightness, and the brightest color is always white. Which is why pushing things ever brighter in photo editing eventually turns them white, because that is the brightest thing possible on screen or print.
</p>

<p>
But this is a limitation of the display, not the editor or the recording. Thus it makes sense to edit photos with a physical understanding of light, where making things brighter does not make them whiter. Consider sharpening, or color grading, or contrast adjustments: All of these can push pixels brighter or darker, but really shouldn't suddenly whiten them at some arbitrary brightness. In the new scene-referred Darktable, colors are squeezed into a viewable or printable form only at the very end of the processing, retaining their physical properties for as long as possible. In most other tools, the squeezing is done early on, and edits hobbled thereafter.
</p>

<p>
In practice, this means Darktable can change tones with any number of tools without losing color information: the tone equalizer, or the rgb curve, or levels rgb, or the contrast equalizer, or sharpening, or color balance all manipulate tones without fear of losing highlight information. Only filmic rgb at the very end determines which bright pixels to turn white. In a way, the scene-referred part of the pipeline feels like raw editing, while the rest feels like editing a JPEG. Contrast this with Capture One, where only the sliders in the Exposure and High Dynamic Range modules can recover bright pixels from white, but e.g. Clarity, Levels, and Curve can not. After getting used to the scene-referred way of working, this seems like an arbitrary limitation, and really makes Levels and Curve less useful than they should be.
</p>

<figure style="width: 100%; text-align: center;">
<a href="/static/2021-09/darktable tone eq and exposure.png" target="_blank"><img width="75%" src="/static/2021-09/darktable tone eq and exposure.png" alt="Darktable screen layout with tone equalizer and exposure module opened" /></a>
<figcaption>Darktable's main development screen with the <em>tone equalizer</em> and <em>exposure</em> module</figcaption>
</figure>

<p>
Interestingly, this leads to a somewhat different editing workflow in Darktable compared to Capture One. Since the scene-referred pipeline is mostly nondestructive, I can play with the overall tonality with abandon, safe in the knowledge that I will be able to recover any lost detail later. Thus I commonly use the <i>exposure</i> slider to expose for my mid-tones, and then reign in my burning highlights with the tone equalizer<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup> or filmc rgb <i>white relative exposure<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup></i>. In Capture One, digital overexposure is much more difficult to recover than underexposure, so I usually use the high dynamic range tools to underexpose slightly, and then recover mid-tone exposure with the high dynamic range <i>shadows</i> slider or tone curve. While these two workflows are largely equivalent, I find it interesting that Darktable can go either way, while Capture One can not.
</p>

<p>
A related area of rapid development in Darktable has been the color balance rgb module, and color calibration. Both of these allow for very fine-grained control over various aspects of color, handily parametrized by hue or tone or channel. There is some subtlety in the <a href="https://www.darktable.org/usermanual/3.6/en/special-topics/color-management/color-dimensions/">various controls</a> for "colorfulness", "vibrance", "chroma", "brilliance", and "saturation" that took some learning. But it also taught me to see color in a more nuanced way, which is a good thing. In mixed lighting, I can now use several instances of color calibration modules<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup> for different image areas, producing more natural results that I am capable of in Capture One.
</p>

<p>
A particular pain point in Darktable 3.4 and Capture One was the rendering of colored highlights. In Darktable 3.4, bright colors often turned weirdly radiant, and then aggressively desaturated, with a sharp and unnatural edge in between. I don't quite know why, but this problem seems much reduced in 3.6. Both issues are now dealt with quickly and cleanly with a quick tug on the filmic rgb white relative exposure slider. A real boon that slider is. Now I just wish it didn't affect contrast quite so much and didn't also influence shadows, despite its name. Oh well, a man can dream. Capture One had the opposite problem, and sometimes wisted colored highlights into bright primary colors before desaturating, leading to cyan skies and yellow skin at the fringes of overexposure. This is still one of my major complaints about Capture One.
</p>

<p>
My last point of struggle with Darktable has long been the rendering of colors of my Fujifilm camera. Something about the colors always seemed off, in a way they weren't in Capture One. Greens too blue, browns too magenta, and skin too pink. After quite some experimentation, I found that this was simply due to Fujifilm depending on a bit of proprietary color magic for appropriate rendering. I now apply one of <a href="https://blog.sowerby.me/fuji-film-simulation-profiles/">Stuart Sowerby's LUTs</a> in chromaticity blending mode after filmic rgb. This leaves tonal adjustments fully to Darktable, but fixes the awkward colors perfectly. And it even allows me to play with the film simulations Fuji is famous for.
</p>

<figure style="width: 100%; text-align: center;">
<a href="/static/2021-09/darktable filmic and lut.png" target="_blank"><img width="75%" src="/static/2021-09/darktable filmic and lut.png" alt="Darktable with lut 3D in chromaticity blend mode after filmic rgb" /></a>
<figcaption>A LUT is applied in chromaticity blend mode after <em>filmic rgb</em></figcaption>
</figure>

<p>
Actually, this highlights a unique strength of Darktable: the order of modules in the image editing pipeline is customizable, and most modules can be applied with masks and blending modes. Only since I used Capture One for a few months did I understand how powerful this concept really is. The key difference is that "layers" in Capture One (et al) merely apply the image editing pipeline with different parameters in different places<sup><a id="fnr.4" class="footref" href="#fn.4" role="doc-backlink">4</a></sup>, while Darktable's modules actually apply sequentially. This enables true incremental editing, such as fixing white balance correctly for one part of the image, then applying another level of white balance just for the blue parts. Or fixing colors in a LUT <i>after</i> all the tonal edits, without fear of destroying highlights or shadows in the process.
</p>

<p>
So overall, I am very happy with Darktable in its latest iteration. As always, there are plenty of nitpicks I could bring forward, such as being a bit sluggish in operation, and the UI could be streamlined a bit<sup><a id="fnr.5" class="footref" href="#fn.5" role="doc-backlink">5</a></sup>. But it has once again displaced Capture One for my own work, and it makes me happy.
</p>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">similar to the high dynamic range module, but more fine-grained</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">essentially a tone curve adjustment</p></div></div>

<div class="footdef"><sup><a id="fn.3" class="footnum" href="#fnr.3" role="doc-backlink">3</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">the new way of doing white balance</p></div></div>

<div class="footdef"><sup><a id="fn.4" class="footnum" href="#fnr.4" role="doc-backlink">4</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">i.e. you can fully desaturate a picture to black-and-white, then "recover" saturation in a layer</p></div></div>

<div class="footdef"><sup><a id="fn.5" class="footnum" href="#fnr.5" role="doc-backlink">5</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">the new quick access panel in 3.6 has already helped a lot!</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2021-09-04-a-review-of-darktable.html</link>
  <guid>https://bastibe.de/2021-09-04-a-review-of-darktable.html</guid>
  <pubDate>Sat, 04 Sep 2021 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Camera Resolution]]></title>
  <description><![CDATA[
<p>
Some of my photographic lenses are reknown for their outstanding sharpness, others are said to be mediocre. But somehow I never quite saw a big difference in sharpness between them. Do older lenses have less resolution than the newer ones? Can a dedicated prime lens resolve more detail than a multi-purpose zoom lens? Let's find out.
</p>

<p>
These questions recently came to a head for me, in the choice between two compact cameras: <a href="https://camerasize.com/compact/#566,819,ha,f">A Fujifilm X100T, 16 MP, with a 23 mm lens, and a Ricoh GR III, 24 MP, with an 18 mm lens</a>. In the last few months, I grew to like the X100T's 23 mm viewpoint, but did not enjoy how bulky the camera is in comparison to the GR III. So I wondered if I could replace the X100T with the Ricoh GR III and simply crop to 23 mm.
</p>

<p>
Being a scientist and all that, I set up an experiment: I printed out a <a href="https://www.graphics.cornell.edu/~westin/misc/res-chart.html">resolution chart</a>, set my cameras on a tripod, and took pictures with all my cameras such that the chart filled a similar portion of each image. Base ISO, two-second timer, processed in Capture One. White balance and contrast were equalized.
</p>

<figure style="text-align: center;">
<a href="/static/2021-05/comparison.svg"><img src="/static/2021-05/comparison.svg" alt="camera resolution comparison" width="80%"/></a>
<figcaption>Red bars indicate the point where some lines are no longer distinguishable, i.e. the limit of the system's resolution.</figcaption>
</figure>

<p>
Each row in the above grid is one camera/lens/focal length combination, taken at the brightest aperture in the left column, and at the sharpest aperture in the right column. The text on the left shows photographic parameters, and the text on the right image parameters. The red line is the spot on the chart where some lines start to blend together, the limit of the image's resolution, as judged by my eyeballs. Depending on the exact framing, DPIs vary somewhat between the images, but generally at a factor of around √(̅2̅4̅/̅1̅6̅)̅ = 1.22 between the 24 MP images and the 16 MP images. The bottom row shows a synthetic image at simulated 24 MP / 380 DPI and 16 MP / 280 DPI.
</p>

<p>
From these images, the biggest contribution to resolution seems to be sensor megapixels. All 24 MP images resolve closer line pairs than any 16 MP image. This could also be a hint that lenses seem to generally outresolve their sensors.
</p>

<p>
Looking closely at the images, another hint becomes visible: aliasing is visible in all images. This is only possible if lens resolution is higher than sensor resolution.
</p>

<p>
Frankly, this is a rather big surprise to me. Reading discussions on the internet had predisposed me to believe that some lenses should be much higher resolution than others, and my big travel-zoom in particular should be terribly soft. From my measurements however, I see no evidence of this claim. All of these lenses outresolve their sensors, and differences between lenses is rather miniscule in general.
</p>

<p>
Another common wisdom is that lenses wide open are less sharp than stopped down. In this test sample, this seems to be true for the X100T's, and to a lesser extent for the LX100, and the Fujifilm XF 60. All other lenses do not show significant (!) differences between apertures. And even for the affected lenses, the difference in resolution is not dramatic.
</p>

<p>
However, resolution is not sharpness. While line pairs may remain resolvable, their edges do lose definition at wide-open apertures on the Fujifilm XF 18-135 at some focal lengths, and the X100T. These lenses definitely need at least additional sharpening at wider apertures. Contrast is also visibly different, but I chose to edit out contrast differences to keep the graphs legible. Generally, the Ricoh GRs' lenses (particularly the GR I) were by far the most contrasty of these lenses.
</p>

<p>
Another interesting comparison can be drawn between the synthetic images in the bottom row and the camera exposures above: None of the 24 MP images reach the resolution of the synthetic image, perhaps due to demosaicing artifacts. However, the 16 MP exposures are very close to the synthetic image. I don't yet know how to interpret this.
</p>

<p>
Speaking of demosaicing however, there does not seem to be a difference in resolution between the X-Trans Fujifilm sensors and the Bayer Ricoh/Panasonic sensors. I also checked whether a different raw developer would make a difference, but did not find anything noteworthy.
</p>

<p>
Overall, this experiment has taught me that all my lenses are high resolution, and that lens resolution in general is probably not a topic worth fussing over. Subpixel patterns are equally unimportant. Instead, lenses do differentiate themselves in contrast and sharpness, and camera sensors in megapixels. And finally, the tiny GR III in crop mode can indeed outresolve the X100T, and out-contrast and out-sharpness it as well.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2021-05-27-camera-resolution.html</link>
  <guid>https://bastibe.de/2021-05-27-camera-resolution.html</guid>
  <pubDate>Thu, 27 May 2021 16:45:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Books of 2020]]></title>
  <description><![CDATA[

<div id="outline-container-org46555eb" class="outline-2">
<h2 id="org46555eb">Chickenhawk</h2>
<div class="outline-text-2" id="text-org46555eb">
<figure style="float:left">
<img src="/static/2021-05/chickenhawk cover.jpg" alt="chickenhawk cover" width="150px"/>
</figure>

<p>
Most first hand accounts of wars I have read are written by a somewhat amateur author. Not this one. Robert Mason infused his terrifying tale with plenty of drama and humanity, and managed to write one of the best personal military history I have ever read.
</p>

<p>
Part of it is surely the subject matter, as I am a huge fan of aviation and its lore. And part of it is that I haven't yet read a lot about the Vietnam War.
</p>

<p>
But either way, I could not put this book down. Every mission seems to be more dramatic than the last, and you can see Mason's flying and survival skills just barely keeping up with the challenge. You can also viscerally feel the surviver bias at work, with plenty of close calls and dead friends. It's terrifying and thrilling at the same time.
</p>

<p>
And towards the end, the book truly surprised me with a very frank account of PTSD and the life of a veteran, which I hadn't read anywhere else in this level of clarity.
</p>

<p>
I cannot recommend this book enough. Perhaps a bit depressing at times, but an utterly compelling story, and without a doubt one of the best books I have ever read.
</p>
</div>
</div>

<div id="outline-container-orgc0c6abf" class="outline-2">
<h2 id="orgc0c6abf">Mountain Light</h2>
<div class="outline-text-2" id="text-orgc0c6abf">
<figure style="float:left">
<img src="/static/2021-05/mountain light cover.jpg" alt="mountain light cover" width="150px"/>
</figure>

<p>
Quite simply, the best photography book I have ever read. From the era of color film, that short time between the black-and-white darkroom and photoshop, where pictures really couldn't be edited. It all came down to the skill of the photographer, which makes a book from this era much more useful than its darkroom-edited predecessors or photoshopped successors.
</p>

<p>
Besides that, the story of an avid adventurer who took part in several expeditions to climb the most difficult mountains in the world for the first time, and document life in the most remote places on earth before man could ever touch them.
</p>

<p>
All in all, a fantastic book of outdoorsmanship, adventures, and photography, three things I love dearly.
</p>
</div>
</div>

<div id="outline-container-org34554d3" class="outline-2">
<h2 id="org34554d3">Two Years Before the Mast</h2>
<div class="outline-text-2" id="text-org34554d3">
<figure style="float:left">
<img src="/static/2021-05/two years before the mast cover.jpg" alt="two years before the mast cover" width="150px"/>
</figure>

<p>
The story of the young author joining a trader ship to the US west coast, in 1834, when it was still largely uninhabited and wilderness. They traveled to many a well-known place, such as San Francisco or Santa Barbara, but these places were still merely trading outposts and missions.
</p>

<p>
At the same time, the author chronicles a sailor's life on board the last generation of sailing vessels, just before they were replaced by steamers. He joined the ship on a two-year-or-so contract around the American continent, on an entirely self-sufficient ship with only the occasional sighting of a fellow ship or the lighting of cargo in a trading depot. Which is an utterly fascinating historical perspective considering that the story happens more-or-less at the same time as the comparatively modern-seeming Sherlock Holmes.
</p>

<p>
But a true eye-opener happens at the very end, where the author re-visits San Francisco later in his life. The city by then has grown to a bustling trade town with regular ferry routes and rail connections, churches and pubs, and all the amenities of modern life. It is hard to believe how such industry would grow from these humble beginnings in just a few decades.
</p>
</div>
</div>

<div id="outline-container-org67f6b7e" class="outline-2">
<h2 id="org67f6b7e">Bobiverse: We Are Legion / For We Are Many / All These Worlds</h2>
<div class="outline-text-2" id="text-org67f6b7e">
<figure style="float:left">
<img src="/static/2021-05/we are legion cover.jpg" alt="we are legion cover" width="150px"/>
</figure>

<p>
Like good candy, I just couldn't stop reading. The story of a regular guy, uploaded into a colony ship as an AI, roaming the galaxy, and exploring the boundaries of what it means to be human. Which sounds much more philosophical than it actually is. The book is written in a lighthearted and fast-paced style that I could hardly put down. I read the first book in one week, and immediately followed through with book two and three.
</p>

<p>
And it actually comes to a satisfying end in the third book, instead of methastesizing into a franchise, which I can't praise highly enough. Perhaps a little bit superficial and handwavy at times, but a thoroughly good time for a science fiction fan.
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-books.html">books</a> ]]></description>
  <category><![CDATA[books]]></category>
  <link>https://bastibe.de/2021-05-05-books-of-2020.html</link>
  <guid>https://bastibe.de/2021-05-05-books-of-2020.html</guid>
  <pubDate>Wed, 05 May 2021 17:14:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[A Review of the RAW Photo Editor Capture One]]></title>
  <description><![CDATA[
<p>
About half a year ago, my second child was born, and all that precious free time I had used for photo editing evaporated. So I started looking for faster photo editor, as a temporary replacement for <a href="https://www.darktable.org/">Darktable</a>. Based on my <a href="https://bastibe.de/2020-05-01-raw-developer-comparison.html">research last time</a>, I chose <a href="https://www.captureone.com/en">Capture One</a>. During the last six months, I got to know the program well, and want to share my thoughts on it, and how it compares to Darktable.
</p>

<p>
Let's start with a bit of background about my photography, to put my views into context. I learned photo editing on Linux, with <a href="https://www.darktable.org/">Darktable</a>, mostly for documenting my travels and family. I gather that a photographer who does not know Lightroom is a bit of an oddity. But it should provide an interesting perspective for the purposes of this review. Furthermore, my interest in post processing is not purely artistic. Being a signal processing scientist, I can't help but analyze the underlying image processing algorithms, and am perhaps more annoyed by certain editing artifacts than most people.
</p>

<p>
In terms of photography, I tend towards quick reactionary shooting of the fleeting moments of my family's life. Mostly because I prefer to spend my time playing with my kids instead of pointing a camera at them. I am therefore perhaps a bit more tolerant of slight imperfections in terms of focus and exposure than is usual. This also means I value my camera/editor's capability for recovering misjudged exposures or imperfect lighting very highly.
</p>

<p>
Most review articles of photo editing software are conducted from only a short glance at the contesting programs, since spending the months necessary to get to know each program is usually neither practical nor affordable. But due to my particular circumstances, the present text actually comes from a few months of more-or-less exclusive use of Capture One, on about 30 thousand pictures, of which I edited about 2000 (all new, not just re-edits of old ones, and implicitly the incentive to recreate another program’s rendering).
</p>

<figure style="width: 100%; text-align: center;">
<a href="/static/2021-05/develop screen.png" target="_blank"><img width="75%" src="/static/2021-05/develop screen.png" alt="Capture One screen layout" /></a>
<figcaption>Capture One's main develop screen </figcaption>
</figure>

<p>
So, Capture One. It is very fast. You move a slider, you see the results of that change immediately, even on my lowly Surface 7 Pro tablet. But this focus on speed actually goes deeper than just slider movements: I discovered that many parts of the application seemed actively optimized for quick operation, which allows me to process pictures much more quickly. This was frankly a revelation in the time-starved months after my second baby’s birth.
</p>

<p>
As an example of how much quicker Capture One's default workflow is than Darktable's, here's my usual editing flow in Darktable: I start with fixing exposure, in the Exposure module. Then I adjust shadow density and recover highlight color with the black and white sliders in the Filmic RGB module. Then I adjust white balance to taste in the Color Calibration module. Then I crop in Crop and Rotate, then add additional adjustments such as Color Zones, Color Balance, Tone Equalizer, Denoise (Profiled), or Contrast Equalizer. Last come local adjustments if necessary. The thing is, more or less every image needs at least Exposure adjustments, some Filmic RGB tweaking, and cropping. All of these items are situated in different modules in Darktable, each requiring multiple clicks to access the module and then change the value. This is supposed to be improved in the next version of Darktable, which will let you put all your favorite sliders in a custom module. I am very much looking forward to that.
</p>

<figure style="width: 100%; text-align: center;">
<img width="24%" src="/static/2021-05/color calibration.png" alt="Darktable color calibration" />
<img width="24%" src="/static/2021-05/crop and rotate.png" alt="Darktable crop and rotate" />
<img width="24%" src="/static/2021-05/filmic rgb.png" alt="Darktable filmic RGB" />
<img width="24%" src="/static/2021-05/tone equalizer.png" alt="Darktable tone equalizer" />
<figcaption>Darktable's basic controls</figcaption>
</figure>

<p>
In contrast, a similar workflow in Capture One happens entirely on one screen, just by going from one slider to the next:
</p>

<figure style="width: 100%; text-align: center;">
<img width="25%" src="/static/2021-05/basic controls.png" alt="Capture One basic controls" />
<figcaption>Capture One's basic controls</figcaption>
</figure>

<p>
Furthermore, common tools such as cropping, rotating, and the white balance picker are accessible at all times with highly memorable keyboard shortcuts (C, R, W, respectively). Taken as a whole, this allows me to positively blaze through images compared to my Darktable workflow. It took me a while to appreciate how significant this difference was in my use: I now sometimes do a few days’ edits in a spare half hour, which used to be an all-evening affair in my usual Darktable workflow.
</p>

<p>
Which is not entirely Darktable's fault. Assigning custom keyboard shortcuts in Darktable can speed things up, and of course Darktable’s module system is infinitely more powerful, so there's a reason for its complexity. But the above example highlights a bit of a philosophical difference between Darktable’s unflinching priority on user control, and Capture One’s compromise between power and speed. There are upsides and downsides to both, but at this moment in my life, I begrudgingly value speed over power.
</p>

<p>
However, there were also a number of occasions where I missed Darktable’s deep control. Most notably, Capture One’s High Dynamic Range sliders and Clarity controls feel a bit restrictive and oversimplified: It can be hard to control which parts of the image are affected, and the tools are prone to produce artifacts such as halos if not managed carefully. In contrast, Darktable's continuous Tone Equalizer mask gives very precise and adjustable control over the affected area. Similarly, Darktable's Contrast Equalizer can control local contrast at arbitrary wavelet sizes, not just the very small ("Structure") or very big ("Clarity") ones, for example for specifically highlighting tree trunks or bird feathers.
</p>

<figure style="width: 100%; text-align: center;">
<a href="/static/2021-05/darktable.png" target="_blank"><img width="75%" src="/static/2021-05/darktable.png" alt="Darktable develop screen with contrast equalizer" /></a>
<figcaption>Highlighting feather detail with darktable's contrast equalizer</figcaption>
</figure>

<p>
Another annoyance with Capture One can be found in colors at the edges of the tone curve: When pushing exposure, Capture One tends to turn brightly colored highlight towards primary colors such as cyan/magenta/yellow before desaturating them into white. Similarly, shadow recovery sometimes pushes brightness and saturation a bit more strongly for brightly colored shadows than for dull ones, leading to an unnatural glowy effect. These cases are usually easy enough to fix with a quick tug on the shadows/highlights slider or by reigning in the offending color's lightness in the Color Editor, but they smell a bit of a runaway algorithm, which bothers me. Although in direct comparison they bother me less than the various rocks and hard places in Darktable's Filmic RGB chrominance preservation modes.
</p>

<p>
On the topic of bothersome details, Capture One's repair layer seemingly has a mind of its own when deciding whether to create a new control point, or adding to an existing one. The Highlight and White slider in the High Dynamic Range module sometimes can't quite decide whether to move white point, and sometimes lead to lightness reversals around bright objects. More on the algorithmic side, it annoys me that only the Exposure and High Dynamic Range modules have access to the full dynamic range of the raw file, while all the other tools apparently come after the screen transform, and therefore can't reach beyond the black point and white point. This makes Levels and Curve a bit less useful than I'm used to. Demosaicing is also not <i>quite</i> as detailed as Darktable's, although only by a tiny margin.
</p>

<p>
One surprising limitation of Capture One is that its support for cameras and lenses is a bit hit-and-miss. Film simulations are only supported for my Fuji X-T2, but not for the older Fuji X100T, nor the Ricohs or Panasonic. Some of their lens profiles are also laughably bad, and leave obvious reverse-vignetting or barrel distortion when enabled. Frankly, Darktable does better in terms of lens support, despite relying solely on volunteer support.
</p>

<p>
In terms of UI, Capture One is generally well-organized and easily configurable. But there is a constant stumbling block in the Layers module that I find very annoying: many of Capture One's tools automatically create new layers, but deselecting the tool does not deselect the layer. As delightfully easy it is to press B for the brush and paint in some Clarity, as unnecessarily laborious it is to then spend three clicks to slide open the Layers module and select the background layer again to resume editing. Or alternatively, wonder why your edits don't work while you <i>don't</i> have the background layer selected. It's a true pain.
</p>

<figure style="width: 100%; text-align: center;">
<img width="25%" src="/static/2021-05/layers.png" alt="Capture One layers" />
<figcaption>With a layer selected, edits only affect the layer</figcaption>
</figure>

<p>
As the last point of the nit picking, I was disappointed by the number of minor technical bugs I encountered in my use of Capture One: Half the time, Capture One starts half zoomed-in, and leaves me scratching my head at what weird compositions I chose for a few seconds. And the main, zoomed-out view is weirdly blurry if you use two displays with different DPI. Both of these issues are well-documented on their forums for several releases, but have not been fixed. For the exorbitant price that Capture One commands, such issues and customer communication are frankly unaccetable.
</p>

<p>
Finally, a few words about the library module and file organization. At first glance, I hated Capture One’s library. You have to import every single directory manually (I organize my images in daily directories), all the edits go into a central catalogue and nowhere else, and the sidecar files contain no editing information. But then someone told me a much better way: Instead of using Capture One’s <i>Catalogue</i>, create a <i>Session</i>, but ignore all those pre-built input and output directories, as well as the import button, and instead simply navigate to any old directory on your computer with the sidebar file browser. This is clearly not how sessions are meant to be used. But it actually works reasonably well, and puts editing information in a subdirectory next to the raw file.
</p>

<p>
On the whole, I grew to quite like Capture One, despite its flaws, mostly for its streamlined user interface and speed of operation. In terms of image quality, I honestly didn’t see much difference between Darktable and Capture One. But perhaps I am not the most discerning of users, either, as my focus is not on crazy detail recovery or the more technical arts of macro or astro. When it comes to control, I occasionally felt restricted and, dare I say, patronized by Capture One. But the speed of operation and general good-enough-ness of the image quality are still hard to argue with. I just wish they fixed their UI bugs, and improved their algorithms a bit.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2021-05-04-a-review-of-the-raw-photo-editor-capture-one.html</link>
  <guid>https://bastibe.de/2021-05-04-a-review-of-the-raw-photo-editor-capture-one.html</guid>
  <pubDate>Tue, 04 May 2021 13:24:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[A review of iOS, from an Android user's perspective]]></title>
  <description><![CDATA[
<p>
My Pixel 2 phone received its final software update the other day, and its battery took the occasion to really show its age. So it was time for a new phone. Which is not a decision to make lightly, considering that I spend multiple hours per day using it. And this time, I was inclined to give the iPhone another go, mostly because of Google's gross lack of human decency in the last few years. So, after years of using various Android devices, I bought a used, red, iPhone SE (2020). I made this choice with some trepidations, as my last experience with iOS was an iPad 3 from 2012. These are my experiences.
</p>

<p>
As a seasoned Android user, my first impressions of iOS were a bit of a mess. There are things that swipe up from the bottom, swipe down from the top, to the left of the home screens, to the right of the home screens, and at various permutations of pressing/holding the home button. Everything animates, takes a long time, and moves the viewport around. Particularly annoying is the placement of the back button in the top left corner, i.e. the most-inconvenient place on the entire screen for the arguably most-important gesture of the entire UI<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>. A close second are the context menus that slide out from a long-pressed item, with the menu thus in a different position on the screen every time you long press anything. These things may be less flashy on Android, but are seriously simpler.
</p>

<p>
I also immediately missed Android's customizeable home screen, with freely-positionable app icons and a plethora of useful widgets. iOS is very restrictive in this regard, and seemingly for no good reason. Why is the list of all apps (right-of-homescreen) sorted arbitrarily into nonsensical folders instead of a plain list? Why are app widgets allowed, but only on that weird left-of-the-home-screen screen? Why can't I have a currently-playing widget for my podcast player, a weather radar, or my groceries list? Apparently, iOS 14 has a brand new API that does now allow Android-like widgets in iOS, but at the moment they were only available for Apple's own (useless) apps.
</p>

<p>
My second big stumbling block was the iOS on-screen keyboard. At first glance, I thought it a terribly clunky thing. Actions as simple as inserting a comma require multiple taps, and positioning the cursor seemed almost comically difficult. But then I discovered that the "123" button in the bottom left can be swiped instead of tapped, which makes commas and periods and hyphens available to a quick swipe. That is seriously cool, if slightly hampered by my accidentally activating Control Center instead of swiping from "123" a bit too often. And precise cursor positioning is hidden behind a long-press of the spacebar. Very cool indeed. With these gestures, the iOS on-screen keyboard is actually not bad at all.
</p>

<p>
Autocorrect seems capable as well, and multi-language aware (hear that, Android?). And, mind-blowingly, a triple-swipe on the content area engages undo and redo in the current text area. Albeit a nigh-undiscoverable gesture, this is miles better than Androids undo/redo system (there isn't one). Actually, Android text fields <i>do</i> support undo and redo if you press Ctrl-Z on the keyboard, it's just that no on-screen keyboard has a Ctrl key. This is my number one grievance with Android at the moment (although there are <a href="https://play.google.com/store/apps/details?id=com.catchingnow.undo&amp;hl=en_US&amp;gl=US">workarounds</a>).
</p>

<p>
As a summary to the keyboard situation, I came to respect the iOS keyboard. I still miss a German "ß" key, more control about the autocorrect system, and a more modern design. But it works reasonably well. Better than Android's stock keyboard for sure.
</p>

<p>
My second big hurdle with iOS was the camera. Just like my Pixel's camera, the iPhone takes perfectly acceptible photos. But everything else is just plain worse than on Android. It starts with the way you get access to the camera, either by swiping right on the lock screen, or by tapping the camera app on the home screen. On Android, you double-click the lock button to start the camera, then hit the volume button to take a photo. Not only is this significantly faster, it also requires no ungloved finger, and no look onto the screen. And it doesn't make that abominable shutter sound, either, that the iPhone requires (unless the entire phone is silenced or you take video).
</p>

<p>
When I take a picture with my phone, it is because I don't have a dedicated camera at hand. Considering the number of cameras I own, this is most likely to happen when I need a camera <i>fast</i>. Thus the speed from pants to picture is extremely important to me, and this is a clear victory for Android. And additionally, Pixel phones have supported stacked RAWs since the original Pixel<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup>, and offer quite a comprehensive image editing suite right in the stock camera app. And I prefer the Pixel's relatively neutral rendering over the iPhone's oversharpened, over-denoised, waxy images. But that might be just me.
</p>

<p>
At this point, I had more or less given up on iOS, and bought a Pixel 4a, which is probably Android's closest competitor to the iPhone SE.
</p>

<p>
Beyond the camera, there were a number of annoyances with iOS that I found hard to get used to. Like the fingerprint reader on the SE being very unreliable for me (50% miss rate), and awkwardly requiring a distinct push to activate the home button, where the Pixel's is quicker and in a more convenient location. The home button is in fact not a button, but an immovable touch pad that fakes a button-like behavior with a little rumble effect when pressed uncomfortably hard. Pressing a hard surface really hard did not get comfortable to me, especially not when invoking the multi-tasking switcher with a double-press. And it's awkwardly placed at the very bottom of the device, where my thumb does not rest with any kind of force in normal usage. Another real problem is the lack of third-party browsers<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup>, which just leaves you in the cold should a website not work in Safari, or should you dislike Safari's rendering or its very limited ad-blockers. I was particularly annoyed by Safari's context menu for links, which slowly slides out from the link's location, often extending far outside of the screen. Thus opening links in new tabs is just awkwardly slow and annoying in Safari, where Android's more utilitarian menu gets the job done much quicker. Although a phone with a bigger screen might mitigate this problem somewhat.
</p>

<p>
On the topic of animations in general, one of my favorite features in Android is the animation speed setting in the Developer settings. If you want to feel like you got a new, faster phone, just set the animation speed to 0.5x, and marvel at the newfound snappiness of everything.
</p>

<p>
Apps in general feel annoyingly restrictive on iOS. Where is a true Firefox, with addons? Where is a Youtube player that can play a YouTube video in the background while the screen is locked, or block ads (NewPipe is the bee's knees!). Or a file synchronization tool that can actually synchronize useful data outside of its own sandox? In fact, my original hopes for iOS were driven by my memory of the fabled higher quality apps available only on the App Store. Looking at some of my old favorites on the SE however, I was forced to take off those rose-tinted glasses. These apps might have been radical back in the day, but the world has moved on. I don't see a pervasive difference in app quality between iOS and Android any longer. Of course iOS apps do still cost a more money on average, and often can't be test-driven without paying. That two-hour free return policy on the Play Store is seriously genius.
</p>

<p>
Additionally, there were a number of odd problems with the iPhone SE that I found hard to make sense of. For example, apps were very frequently getting booted out of memory. So much so in fact, that often my RSS feeds would not refresh in the background, and podcasts would not download. Even though the iPhone SE sure does have a lot less memory than the Pixel 4a, I hadn't expected this to be an actual problem<sup><a id="fnr.4" class="footref" href="#fn.4" role="doc-backlink">4</a></sup>. And the iPhone would frequently misunderstand a vertical swipe for a horizontal one, or initiate an edge swipe when my finger was still clearly on the screen; My bluetooth headphones sounded noticeably worse, with a strange clipping artifact that should not be there; Significantly worse cell reception and voice quality; Low contrast and tiny text on lock screen notifications; And only barely adequate battery life. And let's not even talk about the stupid Lightning cable, the (comparatively) laggy and tiny TFT screen, the lack of a podcast client I like, and my horrible experiences during the setup process.
</p>

<p>
So, in summary, the iPhone SE was not for me. Don't get me wrong, it's a nice enough phone, and probably enough of a smartphone for most people. But there were a number of issues with both its hardware and its software, where I found Android and the Pixel 4a plainly more productive. Which is surprising, as my mind still had iOS pegged as the premium alternative, that I would totally buy if I wasn't too cheap for it. But in actual use I was annoyed at its preference of form over function, with many a distracting animation and a number of glaring ergonomic mistakes. Well, another lesson learned. The only truly significant advantage of iOS remains its vastly superior software support story: The SE will probably receive software updates until 2025 or 2027, where the best-in-class Pixel 4a will definitely expire in 2023.
</p>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">in some places, a right swipe can be used instead of the back button. But the behavior is too inconsistent to be useful</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">what Apple calls "ProRAW", and only makes available in the iPhone 12. iOS does support ordinary RAW, but only in third-party camera apps, and anyway non-stacked RAW files are rather useless from a tiny phone sensor</p></div></div>

<div class="footdef"><sup><a id="fn.3" class="footnum" href="#fnr.3" role="doc-backlink">3</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">there are different browsers, but they are all required to use Safari's web renderer.</p></div></div>

<div class="footdef"><sup><a id="fn.4" class="footnum" href="#fnr.4" role="doc-backlink">4</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">I hear this might have been a bug in iOs 14.3? What this says about the software quality of iOS in general is even more troubling, however.</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-computers.html">computers</a> <a href="https://bastibe.de/tag-ui.html">ui</a> ]]></description>
  <category><![CDATA[computers]]></category>
  <category><![CDATA[ui]]></category>
  <link>https://bastibe.de/2020-12-27-ios-and-android.html</link>
  <guid>https://bastibe.de/2020-12-27-ios-and-android.html</guid>
  <pubDate>Sun, 27 Dec 2020 14:32:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Differences Between Camera Sensors]]></title>
  <description><![CDATA[
<p>
Most cameras have the option to capture <i>raw</i> images, i.e. un-processed image data right from the image sensor. In theory, these images are pure physical measurements of light, and should therefore be very comparable between cameras. But are they? To investigate, I took a <i>raw</i> picture of <a href="https://en.wikipedia.org/wiki/ColorChecker">a color target</a> with each of my five cameras, and compared their output.
</p>

<p>
Capturing accurate colors is a surprisingly intricate matter, as the color depends on the spectrum of the illumination, the reflective spectrum of the colored object, and the color filters in the camera. I normalized the illumination by taking pictures on an overcast day outside<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>, and used a standard color target with 24 colored patches of a certified color.
</p>

<p>
The resulting colored spectra are captured on the camera sensor by photon counters behind three color filters “red”, “green”, and “blue”<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup>, which differ from camera to camera in their spectral sensitivity. The recorded colors then get projected on a computer screen with another set of “red”, “green”, and “blue” LEDs of some different spectral makeup, or printed in three or more inks on paper. And this is then seen with eyes of yet another set of “red”, “green”, and “blue” retinal cells. Let's leave it at <i>color is complicated</i>.
</p>

<p>
At any rate, I took pictures at base ISO in <i>raw</i>, white-balanced and exposed for the third grey patch, and adjusted in saturation on the red patch. Here are the colors on the color checker and the recorded colors of my cameras:
</p>

<img style="width:70%;padding-left:15%;padding-top:5px;padding-bottom:10px" src="/static/2020-10/Colorchecker.svg">

<p>
The image shows the 24 colored patches of the color target<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup>. Within each patch, five rectangles show the recorded color of (in reading order) the Pentax Q7, the Ricoh GR, the Panasonic LX100, the Fujifilm X-T2, and the Google Pixel 2.
</p>

<p>
Due to my exposure and white balance calibration, the third grey patch is completely equalized and shows no difference between the cameras and the target. The “Light Skin” patch (second on the first row) is also very close to equal, which is an important sanity check for my measurement procedure, as skin tones are optimized by all cameras. Seeing that the skin color patch is one of the most similar hopefully indicates that I did not do anything gravely wrong.
</p>

<p>
The last row shows greys, which are very similar across cameras (excluding the white patch for now). This indicates that RAW values indeed correspond to photon counts, with little additional processing. I have no idea why the white patch is off. Perhaps due to specular reflections on the white patch? Color is complicated.
</p>

<p>
As for the other colors, the Panasonic LX100 (center) and the Fujifilm X-T2 (bottom left) seem to record somewhat more accurate colors than the other three cameras. The Pentax Q7 (top left) and Ricoh GR (top right) seem comparatively weak across the board. The Panasonic (center) is great in darker blues and reds and greens, but somewhat weaker in yellows and pastels. The Fujifilm (bottom left) is very good in almost all colors, with pastels somewhat weaker than darker colors. The Google Pixel 2 (bottom right) is better in reds and greens and yellows than in blues and oranges. Pastel colors in general seem weaker than darker colors, which might be due to the same process that affected the white patch as well.
</p>

<p>
I think I learned something from this experiment: There are indeed color differences between cameras even when shooting RAW, but they are relatively minor. Whenever I see larger differences in my pictures, they are likely (easily correctible) white balance differences, and not sensor differences. When in doubt however, my Panasonic LX100 and Fujifilm X-T2 do capture more lifelike colors than my other cameras.
</p>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">any kind of artificial light is comparatively terrible for color reproduction!</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">in quotes, because colors are three-channel information, and we're talking about single channels here.</p></div></div>

<div class="footdef"><sup><a id="fn.3" class="footnum" href="#fnr.3" role="doc-backlink">3</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">encoded as sRGB, which might or might not be displayed correctly on your screen, depending on your OS, your browser, your settings, your room's illumination, and your screen. Color is complicated.</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2020-10-26-differences-between-cameras.html</link>
  <guid>https://bastibe.de/2020-10-26-differences-between-cameras.html</guid>
  <pubDate>Tue, 27 Oct 2020 10:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Lenses Matter]]></title>
  <description><![CDATA[
<p>
A common trope in discussions about cameras on the internet is: “sensor size trumps all”, and as a corollary, “smartphone cameras suck”. Which is obviously false to anyone who has ever taken a good picture on a smartphone (with its tiny sensor).
</p>

<p>
The argument, however, goes like this: Bigger pixels<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup> can capture a greater dynamic range, and bigger sensors are made from bigger pixels. Therefore, and here is the dangerous leap, cameras with bigger sensors take better pictures.
</p>

<p>
But I currently have a bit of time on my hands, and way too many cameras, so let's try it out, shall we?
</p>

<p>
My five contestants are:
</p>

<img style="width:70%;padding-left:15%;padding-top:5px;padding-bottom:10px" src="/static/2020-10/cameras.jpg">

<ul class="org-ul">
<li>A <a href="https://en.wikipedia.org/wiki/Pixel_2">Google Pixel 2</a>, with a 12.2 MP 5.75 × 4.32 mm “1/2.55 in” sensor from 2017, and a 3.8 mm f/1.8 lens (27 mm f/13 equivalent, crop 7.14),</li>
<li>A <a href="https://en.wikipedia.org/wiki/Pentax_Q7">Pentax Q7</a>, with a 12 MP 7.44 × 5.58 mm “1/1.7 in” sensor from 2013, and a 5-15 mm f/2.8-4.5 lens (24-70 mm f/13-22 equivalent, crop 4.76),</li>
<li>A <a href="https://en.wikipedia.org/wiki/Panasonic_Lumix_DMC-LX100">Panasonic LX100</a>, with a 13 MP, cropped 17.3 × 13 mm “micro four thirds” sensor from 2014, and a 11-34 mm f/1.7-2.8 lens (24-75 mm f/3.8-6 equivalent, crop 2.2),</li>
<li>A <a href="https://en.wikipedia.org/wiki/Ricoh_GR_(large_sensor_compact_camera)">Ricoh GR</a>, with a 16 MP 23.7 × 15.7 mm “APS-C” sensor from 2013, and a 28 mm f/2.8 lens (27 mm f/4.2 equivalent, crop 1.5),</li>
<li>A <a href="https://en.wikipedia.org/wiki/Fujifilm_X-T2">Fujifilm X-T2</a>, with a 24 MP 23.6 × 15.6 mm “APS-C” sensor from 2016, and a 18-135 mm f/3.5-5.6 lens (27-200 mm f/5.25-8.4 equivalent, crop 1.5).</li>
</ul>

<p>
So I went for a walk around the neighborhood, and took a few pictures with a bag full of cameras. In particular, I was looking for a high dynamic range scene, in the form of a sunset. All pictures were taken at a low ISO<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup> and underexposed by two stops to account for the backlighting. All images were taken at 27 mm (equivalent<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup>) focal length.
</p>

<p>
<a href="https://photonstophotos.net/Charts/PDR.htm#FujiFilm%20X-T2,Google%20Pixel%202,Panasonic%20Lumix%20DMC-LX100,Pentax%20Q7,Ricoh%20GR">Measurements predict</a> that the dynamic range and noise levels of these cameras should get better as the sensor size increases.
</p>

<br>
<a href="/static/2020-10/scene-1-lightbox.html" target="_blank">
  <div class="lightbox" style="height: 200px">
    <figure>
      <img src="/static/2020-10/Scene 1 Google Pixel 2.thumb.jpg">
      <figcaption>Google Pixel 2</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 1 Pentax Q7.thumb.jpg">
      <figcaption>Pentax Q7</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 1 Panasonic DMC-LX100.thumb.jpg">
      <figcaption>Panasonic LX100</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 1 Ricoh GR.thumb.jpg">
      <figcaption>Ricoh GR</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 1 Fujifilm X-T2.thumb.jpg">
      <figcaption>Fujifilm X-T2</figcaption>
    </figure>
  </div>
</a>

<p>
The first scene was taken essentially in auto mode, and adjusted in Darktable to match roughly in tonality (exposure adjustments of ±0.25EV), but not color. In general, all cameras were able to capture the entire dynamic range of this scene, from the brightest almost-white area around the sun, to the darkest patches in the shade near the waterline.
</p>

<p>
This, right off the bat, is the most important result of this experiment: <i>Most scenes do not have enough dynamic range to matter</i>.
</p>

<p>
Differences appear in the noise levels, which are fairly constant across all cameras, with only the X-T2 being noticeably less noisy than the rest. However, this advantage of the X-T2 is not one of sensor size (the Ricoh GR has a same-size sensor), but simply of being two-generations <i>newer</i>.
</p>

<p>
The largest difference between these photos is instead in flare: The Pixel 2, Pentax Q7 and Ricoh GR are flaring across the entire image, while the LX100 and X-T2 are far more controlled. This is probably because the Pixel 2 and Ricoh GR have collected dust and scratches from my pockets, and the Pentax Q7 lens being somewhat mediocre. The LX100 and X-T2 are in a better condition, and a better design, too. All lenses also show some amount of colorful lens flares to the bottom-right of the sun, particularly in the LX100 and Pentax Q7, and strange, colored rings around the edge of the Ricoh GR's frame.
</p>

<br>
<a href="/static/2020-10/scene-2-lightbox.html" target="_blank">
  <div class="lightbox" style="height: 200px">
    <figure>
      <img src="/static/2020-10/Scene 2 Google Pixel 2.thumb.jpg">
      <figcaption>Google Pixel 2</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 2 Pentax Q7.thumb.jpg">
      <figcaption>Pentax Q7</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 2 Panasonic DMC-LX100.thumb.jpg">
      <figcaption>Panasonic LX100</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 2 Ricoh GR.thumb.jpg">
      <figcaption>Ricoh GR</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 2 Fujifilm X-T2.thumb.jpg">
      <figcaption>Fujifilm X-T2</figcaption>
    </figure>
  </div>
</a>

<p>
To look into these differences between lenses in more detail, the second scene was taken from a slightly different spot, with the lenses stopped down (if possible). This image includes two bright sun spots, one from the sun itself, and one in the reflection on the water.
</p>

<p>
Notably, the Pixel 2, like most smartphones, can not change its aperture. And it produces a bright red flare towards the left edge of the image. The Pentax Q7 again flares dramatically and colorful, and my Ricoh GR's lens is probably beyond cleaning at this point, judging from the massive flare it produces. Again, the standout pictures here are the X-T2 and LX100, with well-defined sun stars and comparatively little flaring. (Note the red dots in the X-T2: these are the phase-detection pixels on the X-T2's sensor reflecting light back into the lens and back on the image.)
</p>

<br>
<a href="/static/2020-10/scene-2-crop-lightbox.html" target="_blank">
  <div class="lightbox" style="height: 200px">
    <figure>
      <img src="/static/2020-10/Scene 2 Crop Google Pixel 2.thumb.jpg">
      <figcaption>Google Pixel 2</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 2 Crop Pentax Q7.thumb.jpg">
      <figcaption>Pentax Q7</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 2 Crop Panasonic DMC-LX100.thumb.jpg">
      <figcaption>Panasonic LX100</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 2 Crop Ricoh GR.thumb.jpg">
      <figcaption>Ricoh GR</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 2 Crop Fujifilm X-T2.thumb.jpg">
      <figcaption>Fujifilm X-T2</figcaption>
    </figure>
  </div>
</a>

<p>
Here is an enlargement of the dark patch at the right edge of the second scene, to judge noise levels and detail in the shadow. Perhaps surprisingly, the differences between these images are not big at all. The X-T2 clearly wins in terms of both shadow detail and noise levels, but by a rather small margin, and only really visible when enlarged. The Pentax Q7 resolves almost no detail in the shadow, but neither does the Ricoh GR. So sensor size does not seem to affect this round.
</p>

<br>
<a href="/static/2020-10/scene-3-lightbox.html" target="_blank">
  <div class="lightbox" style="height: 200px">
    <figure>
      <img src="/static/2020-10/Scene 3 Google Pixel 2.thumb.jpg">
      <figcaption>Google Pixel 2</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 3 Pentax Q7.thumb.jpg">
      <figcaption>Pentax Q7</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 3 Panasonic DMC-LX100.thumb.jpg">
      <figcaption>Panasonic LX100</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 3 Ricoh GR.thumb.jpg">
      <figcaption>Ricoh GR</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 3 Fujifilm X-T2.thumb.jpg">
      <figcaption>Fujifilm X-T2</figcaption>
    </figure>
  </div>
</a>

<p>
This third scene was shot one day later, with settings optimized for optimal image quality: Base ISO, aperture one stop closed from wide open, focused on a high-contrast part of the scene. I processed these images with white balance from a grey card, then edited exposure, contrast, and saturation to match across images. Chromatic aberrations and vignetting were corrected using a profile or by hand. No sharpening was applied, but the highest-quality deinterlacing was selected (AMaZe for Bayer sensors, Markensteijn 3-pass for X-Trans sensors).
</p>

<p>
At this magnification, even my 24in/4K screen only barely hints at differences in sharpness. Which implies that prints up to A3 should be possible from all of these cameras without much difference in perceived sharpness.
</p>

<br>
<a href="/static/2020-10/scene-3-crop-lightbox.html" target="_blank">
  <div class="lightbox" style="height: 200px">
    <figure>
      <img src="/static/2020-10/Scene 3 Crop Google Pixel 2.thumb.jpg">
      <figcaption>Google Pixel 2</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 3 Crop Pentax Q7.thumb.jpg">
      <figcaption>Pentax Q7</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 3 Crop Panasonic DMC-LX100.thumb.jpg">
      <figcaption>Panasonic LX100</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 3 Crop Ricoh GR.thumb.jpg">
      <figcaption>Ricoh GR</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-10/Scene 3 Crop Fujifilm X-T2.thumb.jpg">
      <figcaption>Fujifilm X-T2</figcaption>
    </figure>
  </div>
</a>

<p>
If we crop into these images, differences in detail resolution indeed become apparent. The Pentax Q7 is definitely the least detailed, on account of its soft lens. The Pixel 2 and LX100 show a very similar amount of details, which is a testament to how good modern smart phone cameras truly have become. While the two cameras with the biggest sensors, the Ricoh GR and the X-T2, do resolve visibly more detail, the differences are not dramatic.
</p>

<p>
So does sensor size trump all? From these experiments, I wouldn't say so. Essentially, all of these cameras took decent images. The X-T2 clearly was better than the rest, but not hugely so, while being <i>much</i> bigger and more expensive and newer.
</p>

<p>
While the measured dynamic range differences surely exist, they did not manifest even in a sunrise, so I'm inclined to discount their importance. This is, frankly, not what I expected. The miniscule differences in resolution were equally unexpected.
</p>

<p>
What did however make a big difference was lens quality. Flare control, aperture range, and focal range play a huge role in the resulting image quality. Zooming in (and stopping down) are still the most effective way of extracting more detail from a scene. And having a camera with a secure grip that is quick to operate helps, too. I think I am growing out of sensor size snobbery, is what I'm saying.
</p>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">technically, “sensor elements”, not “picture elements”, i.e. “sensels”</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">lower ISO → less noise.</p></div></div>

<div class="footdef"><sup><a id="fn.3" class="footnum" href="#fnr.3" role="doc-backlink">3</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">the focal length a lens on a 35 mm film camera would need to cover the same angle of view.</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2020-10-16-lenses-matter.html</link>
  <guid>https://bastibe.de/2020-10-16-lenses-matter.html</guid>
  <pubDate>Fri, 16 Oct 2020 12:14:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Dear Computer, We Need to Talk]]></title>
  <description><![CDATA[
<p>
After years of using Linux on my desktop, I decided to install Windows on my computer, to get access to a few commercial photo editing applications. I'll go into my grievances with Linux later, but for now:
</p>

<div id="outline-container-orgb926e7a" class="outline-2">
<h2 id="orgb926e7a">I tried to install Windows, you won't believe what happened next</h2>
<div class="outline-text-2" id="text-orgb926e7a">
<p>
Like I have done many times with Linux, I download a Windows image from my university, and write it to a USB drive, then reboot into the USB drive. The USB drive can't be booted. A quick internet search leads me to a Microsoft Support page on how to <a href="https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/install-windows-from-a-usb-flash-drive">Install Windows from a USB Flash Drive</a>, which says that
</p>

<img style="width:50%;padding-left:25%" src="/static/2020-09/one does not simply.jpg">

<p>
Instead, one has to format the stick as FAT32, make it <i>active</i>, then copy the files from the image to it. So I follow the instructions and open the Disk Management program. It does not offer an option of FAT32, nor for making the partition <i>active</i>. I settle on (inactive) exFAT instead. It doesn't boot.
</p>

<p>
I switch over to Linux, where I can indeed make a FAT32 partition, and I can mark it as <i>bootable</i>, which I take as the equivalent of <i>active</i>. But Linux can not open the Windows image to copy the files onto the USB stick. So back to Windows, for copying the files. Except they can't be copied, because some of them are larger than 4Gb, which can't be written to a FAT32 partition. What now?
</p>

<p>
While researching how to download a different version of Windows 10, I stumble upon the <a href="https://www.microsoft.com/de-de/software-download/windows10">Media Creation Tool</a>, which automatically downloads Windows 10 and writes it to the USB stick correctly. Why was this not pointed out in the article above? Who knows. At any rate, it works. I can finally install Windows.
</p>

<p>
The installation process requires the usual dozen-or-so refusals of tracking, ads, privacy intrusions, and voice assistants. I wish I could simply reject them all at once. And then the install hangs, while "polishing up a few things". Pressing the helpful back button, and then immediately the forward button unhangs it, and the installation completes.
</p>

<p>
Next up are drivers. It feels anachronistic to have to install drivers manually in this day and age, but oh well. The new GPU driver to make screen tearing go away, a driver for my trackball to recognize the third mouse button, a wacom driver, ten or so Intel drivers of unknown utility. The trackball driver is not signed. I install it anyway. The GPU driver does not recognize my GPU and can't be installed. A quick Internet search reveals that my particular AMD/Intel GPU/CPU was discontinued from support by both AMD and Intel, and does not have a current driver. But fora suggest that up to version 20.2.1 of the AMD driver work fine. They don't, the driver crashes when I open images in my photo editor. An even older version published by Intel does work correctly. So now I am running an AMD GPU with an Intel driver from 2018.
</p>

<img style="width:50%;padding-left:25%" src="/static/2020-09/this is fine.png">

<p>
Installing and setting up Firefox and my photo editors works without issue, thank goodness. Emacs has a Windows installer now, which is greatly appreciated. OpenCL and network shares just work. This is why I'm installing Windows next to my Linux.
</p>

<p>
But Windows is still not activated. I copy my university's product key in the appropriate text box, but hesitate: That's for Windows Enterprise, and I'd be just fine with Home. So I cancel the activation without activating. A helpful link in the activation systems sends me to the Microsoft Store to get my very own version of Windows Home for €145, which normally retails for around €95, so that's a no-go. Whatever, I'll go with my university's Enterprise edition. Except the activation box now says my product key is invalid. And the Store now literally says "We don't know how you got here but you shouldn't be here" instead of selling me Windows. After a restart it installs and activates Windows Enterprise, even though I never actually completed the activation.
</p>

<img style="width:70%;padding-left:15%" src="/static/2020-09/this is fine 2.jpg">

<p>
I install Git, but in order to access my Github I need to copy over my SSH key from the Linux install. Which I can't boot at the moment, because installing Windows overwrites the boot loader. This is normal. So I download Ubuntu, write it to the USB stick, boot into it, recover the bootloader, boot into my old install, reformat the stick, copy the files to the stick, boot back into Windows, and the files aren't on the stick. Tough. Boot back into Linux, copy the files onto the stick, <i>eject the stick</i>, boot back into Windows, copy the files to the computer. Great user experience.
</p>

<p>
Now that I have my SSH key, I open a Git Bash to download a project. It says my credentials are incorrect. I execute the same commands in a regular CMD instead of Git Bash, and now my credentials are correct. Obviously.
</p>

<p>
There are several programs that claim to be able to read Linux file systems from Windows. They do not work. But Microsoft has just announced that you will be able to mount Linux file systems from WSL in a few weeks or months. So maybe that will work!
</p>

<p>
I set my lock screen to a slideshow of my pictures. Except my pictures do not show up, and I get to see Window's default pictures instead. An internet search reveals that this is a wide-spread problem. Many "solutions" are offered <a href="https://answers.microsoft.com/en-us/windows/forum/windows_10-start/windows-10-lock-screen-slideshow-not-showing/01975f7f-11e8-457e-a8ef-5b494af135f1">in the support fora</a>. What works for me is to first set the lock screen to "Windows Spotlight", then to "Slideshow". Only in that order will my pictures be shown.
</p>

<p>
I will stop here. I could probably go on ad infinitum if I wanted to. This was my experience of using Windows for one day. I consider these problems relatively benign, in that all of them had solutions, if non-obvious ones.
</p>
</div>
</div>

<div id="outline-container-org1688e83" class="outline-2">
<h2 id="org1688e83">Why install Windows in the first place?</h2>
<div class="outline-text-2" id="text-org1688e83">
<p>
Part of the reason for installing Windows was my growing frustration with Linux. I have been a happy user of KDE of various flavors for about seven years now. But ever since I got into photo editing, things began to become problematic:
</p>

<p>
My photo editor requires OpenCL, but the graphics driver situation on Linux is problematic, to say the least. I generally managed to get RocM running most of the time, but kernel updates frequently broke it, or required down- or upgrading RocM. It was a constant struggle.
</p>

<p>
I wanted to work with some of my data on a network share, but KDE's implementation of network shares does not simply mount them for applications to use, but instead requires each application to be able to open network locations on their own. Needless to say, this worked almost never, requiring many unnecessary file copies. Perhaps Gnome handles network shares better, but let's not open that can of worms.
</p>

<p>
Printing photos simply never worked right for me. The colors were off, photo papers were not supported, the networked printer was rarely recognized. Both for a Samsung printer and an Epson and a Canon. One time a <a href="https://turboprint.info/">commercial printer driver for Linux</a> printed with so much ink it dripped off the paper afterwards. Neither Darktable nor Gimp nor Digikam have a robust printing mode. I generally resorted to Windows for printing.
</p>

<p>
I ran that Windows in a virtual machine. With Virtualbox, the virtual machine would be extremely slow, to the point where it had a delay of several seconds between typing and seeing letters on the screen. VMWare did better, but would suddenly freeze and hang for minutes at a time. Disabling hugepages helped sometimes, for a short while. The virtual machine network was extremely unreliable. Some of these issues were probably related to my using a 4K screen.
</p>

<p>
Speaking of screens, I have two screens, one HighDPI 4k and one normal 1440p. Using X, the system can be either in HighDPI mode, or in normal mode. But it can't drive the two displays in different modes. Thus the second monitor was almost useless and I generally worked only on the 4k screen. With Wayland I would have been able to use both screens in different modes, but not be able to color-calibrate them or record screen casts. Which is completely unacceptable. So I stuck with one screen and X. In Windows, I can use both screens and calibrate them.
</p>

<img style="width:50%;padding-left:25%" src="/static/2020-09/wtf.jpg">


<p>
Additionally, Linux hardware support is still a bit spotty. My SD card reader couldn't read some SD cards because of driver issues. It would sometimes corrupt the SD card's file systems. USB-connected cameras were generally not accessible. The web cam did not work reliably. The CPU fan ran too hot most of the time.
</p>

<p>
So there had been numerous grievances in Linux that had no solutions. Still I stuck with it because so many more smaller issues were actually fixable if I put in the work. In fact I had accumulated quite a number of small hacks and scripts for various issues. I feared that Windows would leave me without recourse in these situations. And it doesn't. But at least the bigger features generally work as advertised.
</p>
</div>
</div>

<div id="outline-container-org4190bb5" class="outline-2">
<h2 id="org4190bb5">Where do we go from here?</h2>
<div class="outline-text-2" id="text-org4190bb5">
<p>
Just for completion's sake, I should really find an Apple computer and run it through its paces. From my experience of occasionally using a Macbook for teaching over the last few years, I am confident that it fares no better than Linux or Windows.
</p>

<p>
Were things always this broken? How are normal people expected to deal with these things? No wonder every sane person now prefers a smartphone or tablet to their computers. Limited as they may be, at least they generally <i>work</i>.
</p>

<p>
There is no joy in technology any more.
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-computers.html">computers</a> <a href="https://bastibe.de/tag-linux.html">linux</a> <a href="https://bastibe.de/tag-windows.html">windows</a> ]]></description>
  <category><![CDATA[computers]]></category>
  <category><![CDATA[linux]]></category>
  <category><![CDATA[windows]]></category>
  <link>https://bastibe.de/2020-09-17-dear-computer-we-need-to-talk.html</link>
  <guid>https://bastibe.de/2020-09-17-dear-computer-we-need-to-talk.html</guid>
  <pubDate>Thu, 17 Sep 2020 10:25:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[How to Write a Dissertation]]></title>
  <description><![CDATA[
<p>
Assembling scientific documents is a complex task. My documents are a combination of graphs, data, and text, written in LaTeX. This post is about combining these elements, keeping them up to date, while not losing your mind. My techniques work on any Unix system on Linux, macOS, or the WSL.
</p>

<div id="outline-container-org24dc8a2" class="outline-2">
<h2 id="org24dc8a2">Text</h2>
<div class="outline-text-2" id="text-org24dc8a2">
<p>
For engineering or science work, my deliverables are PDFs, typically rendered from LaTeX. But writing LaTeX is not the most pleasant of writing environments. So I've tried my hand at org-mode and Markdown, compiled them to LaTeX, and then to PDF. In general, this worked well, but there always came a point where the abstraction broke, and the LaTeX leaked up the stack into my document. At which point I'd essentially write LaTeX anyway, just with a different syntax. After a few years of this, I decided to cut the middle-man, bite the bullet, and just write LaTeX.
</p>

<p>
That said, modern LaTeX is not so bad any more: XeLaTeX supports normal OpenType fonts, mixed languages, proper unicode, and natively renders to PDF. It also renders pretty quickly. My entire dissertation renders in less than three seconds, which is plenty fast enough for me.
</p>

<p>
To render, I run a simple makefile in an infinite loop that recompiles my PDF whenever the TeX source changes, giving live feedback while writing:
</p>

<div class="org-src-container">
<pre class="src src-makefile">diss.pdf: diss.tex makefile $(graph_pdfs)
	xelatex -interaction nonstopmode diss.tex
</pre>
</div>

<p>
We'll get back to <code>$(graph_pdfs)</code> in a second.
</p>
</div>
</div>

<div id="outline-container-org76b666a" class="outline-2">
<h2 id="org76b666a">Graphs</h2>
<div class="outline-text-2" id="text-org76b666a">
<p>
A major challenge in writing a technical document is keeping all the source data in sync with the document. To make sure that all graphs are up to date, I plug them into the same makefile as above, but with a twist: All my graphs are created from Python scripts of the same name in the <code>graphs</code> directory.
</p>

<p>
But you don't want to simply execute <i>all</i> the scripts in <code>graphs</code>, as some of them might be shared dependencies that do not produce PDFs. So instead, I only execute scripts that start with a chapter number, which conveniently sorts them by chapter in the file manager, as well.
</p>

<p>
Thus all graphs render into the main PDF and update automatically, just like the main document:
</p>

<div class="org-src-container">
<pre class="src src-makefile">graph_sources = $(shell find graphs -regex "graphs/[0-9]-.*\.py")
graph_pdfs = $(patsubst %.py,%.pdf,$(graph_sources))

graphs/%.pdf: graphs/%.py
	cd graphs; .venv/bin/python $(notdir $&lt;)
</pre>
</div>

<p>
The first two lines build a list of all graph scripts in the <code>graphs</code> directory, and their matching PDFs. The last two lines are a makefile recipy that compiles any graph script into a PDF, using the virtualenv in <code>graphs/.venv/</code>. How elegant these makefiles are, with recipe definitions independent of targets.
</p>

<p>
This system is surprisingly flexible, and absolutely trivial to debug. For example, I sometimes use those graph scripts as glorified shell scripts, for converting an SVG to PDF with Inkscape or some similar task. Or I compile some intermediate data before actually building the graph, and cache them for later use. Just make sure to set an appropriate exit code in the graph script, to signal to the makefile whether the graph was successfully created. An additional makefile target <code>graphs: $(graph_pdfs)</code> can also come in handy if you want ignore the TeX side of things for a bit.
</p>
</div>
</div>

<div id="outline-container-org53f4df7" class="outline-2">
<h2 id="org53f4df7">Data</h2>
<div class="outline-text-2" id="text-org53f4df7">
<p>
All of the graph scripts and TeX are of course backed by a Git repository. But my dissertation also contains a number of databases that are far too big for Git. Instead, I rely on git-annex to synchronize data across machines from a simple webdav host.
</p>

<p>
To set up a new writing environment from scratch, all I need is the following series of commands:
</p>

<div class="org-src-container">
<pre class="src src-shell">git clone git://mygitserver/dissertation.git dissertation
cd dissertation
git annex init
env WEBDAV_USERNAME=xxx WEBDAV_PASSWORD=yyy git annex enableremote mywebdavserver
git annex copy --from mywebdavserver
(cd graphs; pipenv install)
make all
</pre>
</div>

<p>
This will download my graphs and text from <code>mygitserver</code>, download my databases from <code>mywebdavserver</code>, build my Python environment with <code>pipenv</code>, recreate all the graph PDFs, and compile the TeX. A process that can take a few hours, but is completely automated and reliable.
</p>

<p>
And that is truly the key part; The last thing you want to do while writing is being distracted by technical issues such as "where did I put that database again?", "didn't that graph show something different the other day?", or "I forgot to my database file at work and now I'm stuck at home during the pandemic and can't progress". Not that any of those would have ever happened to me, of course.
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-computers.html">computers</a> <a href="https://bastibe.de/tag-emacs.html">emacs</a> <a href="https://bastibe.de/tag-workflow.html">workflow</a> ]]></description>
  <category><![CDATA[computers]]></category>
  <category><![CDATA[emacs]]></category>
  <category><![CDATA[workflow]]></category>
  <link>https://bastibe.de/2020-05-27-how-to-write-a-dissertation.html</link>
  <guid>https://bastibe.de/2020-05-27-how-to-write-a-dissertation.html</guid>
  <pubDate>Wed, 27 May 2020 18:11:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[How I Record Screen Casts]]></title>
  <description><![CDATA[
<p>
This semester is weird. Instead of holding my "Applied Programming" lecture as I normally would, live-coding in front of the students and narrating my foibles, this time it all had to be done online, thanks to the ongoing pandemic. Which meant I had to record videos. I had no idea how to record videos. This is a writeup of what I did, in case I have to do more of it. You can see the results of my efforts in my <a href="https://bastibe.de/2020-03-20-qt-for-python-tutorial.html">Qt for Python video tutorials</a> and my <a href="https://bastibe.de/2020-05-20-file-parsing-tutorial.html">file parsing with Python video tutorials</a>. Through some strange coincidences, wired.com wrote an <a href="https://www.wired.com/story/anyones-celebrity-streamer-open-source-app/">article</a> about my use of OBS.
</p>

<p>
Working on Linux, I used the <a href="https://obsproject.com/">Open Broadcaster Software</a>, or OBS for short, as my recording program. OBS can do much more than record screencasts, but I only use it for two things: Recording a portion of my screen, and switching between different portions.
</p>

<img src="/static/2020-05/OBS_screenshot.png">

<p>
To this end, I divide my screen into four quadrants. The top left is OBS, for monitoring my recording and mic levels. The bottom left is a text editor with my speaker notes. The top right and bottom right are my two recording <i>scenes</i>, usually a terminal or browser in the top right, and a text editor in the bottom right. The screenshot shows the <i>Editor</i> scene, which has a filter applied to its source to record only the bottom right quadrant. On a 4K screen, each quadrant is exactly full HD.
</p>

<p>
In OBS's settings, I set hotkeys to switch scenes: I use F1 and F2 to select the <i>Browser</i> and <i>Editor</i> scenes, and F6 for starting and stopping recordings. For more compatible video files, I enable "Automatically remux to mp4" in OBS' advanced settings.
</p>

<p>
The second ingredient to my recording setup is KDE, where I assign F3 and F4 to activate the browser or editor window (right click any window → More Actions → Assign Window Shortcut). And to make my recordings look clean, I disable window shadows for the duration of the recording.
</p>

<p>
With these shortcuts, I hit F1 and F3 to switch focus and scene to the browser, or F2 and F4 for the text editor. To make this work smoothly, I disabled these shortcuts within my terminal, browser, and text editor. But always be weary of accidentally getting those out of sync. I don't know how often I accidentally recorded the wrong part of the screen and had to redo a recording.
</p>

<p>
Anyway, with this setup, I can record screen casts with very minimal effort. The last ingredient however is editing; and I loathe video editing. I'd much rather record a few more takes than spend the same time in a video editor. Instead, I record short snippets of a few minutes each, and simply concatenate them with <a href="https://ffmpeg.org/">FFmpeg</a>:
</p>

<p>
Create a file <i>concatenate.txt</i>, that lists all the files to be concatenated:
</p>

<pre class="example">
file part-one.mp4
file part-two.mp4
file part-three.mp4
</pre>

<p>
then run <code>ffmpeg -f concat -i concatenate.txt -c copy output.mp4</code> to concatenate them into a new file <code>output.mp4</code>.
</p>

<p>
The great thing about this method is that it uses the <code>copy</code> codec, which does not re-encode the file. I.e. it only takes a fraction of a second, and does not degrade quality.
</p>

<p>
In summary, this setup works very well for me. It is simple and efficient, and does not require any video editing. The ability to switch scenes is cool and powerful. Still, recording videos is a lot of work. All in all, the 18 videos in the file parsing tutorials took 250 takes, according to my trash directory.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <link>https://bastibe.de/2020-05-19-how-i-record-screen-casts.html</link>
  <guid>https://bastibe.de/2020-05-19-how-i-record-screen-casts.html</guid>
  <pubDate>Tue, 19 May 2020 16:33:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[File Parsing with Python Video Tutorial]]></title>
  <description><![CDATA[
<p>
This video series was produced in the spring of 2020, during the COVID19-pandemic, when all lectures had to be held electronically, without physical attendance. It is a tutorial, in German, for parsing text files, and basic unit testing.
</p>

<p>
If the videos are too slow, feel free to speed them up by right-clicking, and adjusting play speed (Firefox only, as far as I know).
</p>

<p>
You may also download the videos and share them with your friends. Please do not upload them to social media or YouTube, but link to this website instead. If you want to modify them or create derivative works, please contact me.
</p>

<center>
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-nd/4.0/88x31.png" /></a><br />The <span xmlns:dct="http://purl.org/dc/terms/" href="http://purl.org/dc/dcmitype/MovingImage" property="dct:title" rel="dct:type">Qt for Python Video Tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://bastibe.de/2020-03-20-qt-for-python-tutorial.html" property="cc:attributionName" rel="cc:attributionURL">Bastian Bechtold</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/">Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License</a>.
</center>

<div id="outline-container-org9e329af" class="outline-2">
<h2 id="org9e329af">1 Intro</h2>
<div class="outline-text-2" id="text-org9e329af">
<p>
Prerequisites: A basic understanding of Python, and a working installation of python ≥3.6.
</p>

<p>
An overview over the topics discussed in the rest of the videos, and installation of <a href="https://pytest.org">pytest</a>.
</p>

<video controls width="100%">
  <source src="/static/2020-05/01 Intro.mp4" type="video/mp4">
</video>
</div>
</div>

<div id="outline-container-org494536e" class="outline-2">
<h2 id="org494536e">2 INI: First Steps</h2>
<div class="outline-text-2" id="text-org494536e">
<p>
Basic setup, and our first test.
</p>

<video controls width="100%">
  <source src="/static/2020-05/02 INI first steps.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-05/inifile_1.py">inifile_1.py</a> and <a href="/static/2020-05/inifile_test_1.py">inifile_test_1.py</a></p>
</div>
</div>

<div id="outline-container-orgb557838" class="outline-2">
<h2 id="orgb557838">3 INI: Sections</h2>
<div class="outline-text-2" id="text-orgb557838">
<p>
Parsing INI sections.
</p>

<video controls width="100%">
  <source src="/static/2020-05/03 INI sections.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-05/inifile_2.py">inifile_2.py</a> and <a href="/static/2020-05/inifile_test_2.py">inifile_test_2.py</a></p>
</div>
</div>

<div id="outline-container-org4ef0fb8" class="outline-2">
<h2 id="org4ef0fb8">4 INI: Variables</h2>
<div class="outline-text-2" id="text-org4ef0fb8">
<p>
Parsing INI variable assignments.
</p>

<video controls width="100%">
  <source src="/static/2020-05/04 INI variables.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-05/inifile_3.py">inifile_3.py</a> and <a href="/static/2020-05/inifile_test_3.py">inifile_test_3.py</a></p>
</div>
</div>

<div id="outline-container-org9a10d03" class="outline-2">
<h2 id="org9a10d03">5 INI: Bugfixes and Integration Tests</h2>
<div class="outline-text-2" id="text-org9a10d03">
<p>
Parsing difficult values, and comments.
</p>

<video controls width="100%">
  <source src="/static/2020-05/05 INI bugfixes and integration tests.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-05/inifile_4.py">inifile_4.py</a> and <a href="/static/2020-05/inifile_test_4.py">inifile_test_4.py</a></p>
</div>
</div>

<div id="outline-container-org2e66a92" class="outline-2">
<h2 id="org2e66a92">6 INI: Test the Tests</h2>
<div class="outline-text-2" id="text-org2e66a92">
<p>
Tests can be wrong, too.
</p>

<video controls width="100%">
  <source src="/static/2020-05/06 INI test the tests.mp4" type="video/mp4">
</video>
</div>
</div>

<div id="outline-container-orgf63a313" class="outline-2">
<h2 id="orgf63a313">7 CSV: First Prototype</h2>
<div class="outline-text-2" id="text-orgf63a313">
<p>
A simple parser for values without quotes.
</p>

<video controls width="100%">
  <source src="/static/2020-05/07 CSV first prototype.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-05/csvfile_1.py">csvfile_1.py</a> and <a href="/static/2020-05/csvfile_test_1.py">csvfile_test_1.py</a></p>
</div>
</div>

<div id="outline-container-org4be3b70" class="outline-2">
<h2 id="org4be3b70">8 CSV: Quotes</h2>
<div class="outline-text-2" id="text-org4be3b70">
<p>
Parsing quoted values makes everything harder.
</p>

<video controls width="100%">
  <source src="/static/2020-05/08 CSV quotes.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-05/csvfile_2.py">csvfile_2.py</a> and <a href="/static/2020-05/csvfile_test_2.py">csvfile_test_2.py</a></p>
</div>
</div>

<div id="outline-container-orgdc2a7ac" class="outline-2">
<h2 id="orgdc2a7ac">9 CSV: A Few More Features</h2>
<div class="outline-text-2" id="text-orgdc2a7ac">
<p>
Comments and a choice of separators.
</p>

<video controls width="100%">
  <source src="/static/2020-05/09 CSV a few more feature.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-05/csvfile_3.py">csvfile_3.py</a> and <a href="/static/2020-05/csvfile_test_3.py">csvfile_test_3.py</a></p>
</div>
</div>

<div id="outline-container-org7eb602a" class="outline-2">
<h2 id="org7eb602a">10 JSON: Keyword Parser</h2>
<div class="outline-text-2" id="text-org7eb602a">
<p>
Parsing the simplest of JSON expressions.
</p>

<video controls width="100%">
  <source src="/static/2020-05/10 JSON keyword parser.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-05/jsonfile_1.py">jsonfile_1.py</a> and <a href="/static/2020-05/jsonfile_test_1.py">jsonfile_test_1.py</a></p>
</div>
</div>

<div id="outline-container-orgca633eb" class="outline-2">
<h2 id="orgca633eb">11 JSON: Strings</h2>
<div class="outline-text-2" id="text-orgca633eb">
<p>
Parsing JSON strings is not as simple as it seems.
</p>

<video controls width="100%">
  <source src="/static/2020-05/11 JSON strings.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-05/jsonfile_2.py">jsonfile_2.py</a> and <a href="/static/2020-05/jsonfile_test_2.py">jsonfile_test_2.py</a></p>
</div>
</div>

<div id="outline-container-orgf456e7b" class="outline-2">
<h2 id="orgf456e7b">12 JSON: Numbers</h2>
<div class="outline-text-2" id="text-orgf456e7b">
<p>
Numbers in JSON.
</p>

<video controls width="100%">
  <source src="/static/2020-05/12 JSON numbers.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-05/jsonfile_3.py">jsonfile_3.py</a> and <a href="/static/2020-05/jsonfile_test_3.py">jsonfile_test_3.py</a></p>
</div>
</div>

<div id="outline-container-org940e1bf" class="outline-2">
<h2 id="org940e1bf">13 JSON: Data Structures</h2>
<div class="outline-text-2" id="text-org940e1bf">
<p>
The rest of JSON: Objects and Arrays.
</p>

<video controls width="100%">
  <source src="/static/2020-05/13 JSON data structures.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-05/jsonfile_4.py">jsonfile_4.py</a> and <a href="/static/2020-05/jsonfile_test_4.py">jsonfile_test_4.py</a></p>
</div>
</div>

<div id="outline-container-orgc8ac4b6" class="outline-2">
<h2 id="orgc8ac4b6">14 Regular Expressions 1</h2>
<div class="outline-text-2" id="text-orgc8ac4b6">
<p>
How to parse parts of INI files with regular expressions.
</p>

<video controls width="100%">
  <source src="/static/2020-05/14 Regular Expressions 1.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-05/inifile_regex.py">inifile_regex.py</a></p>
</div>
</div>

<div id="outline-container-orgd7b7b52" class="outline-2">
<h2 id="orgd7b7b52">15 Regular Expressions 2</h2>
<div class="outline-text-2" id="text-orgd7b7b52">
<p>
How to parse parts of JSON files with regular expressions.
</p>

<video controls width="100%">
  <source src="/static/2020-05/15 Regular Expressions 2.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-05/jsonfile_regex.py">jsonfile_regex.py</a></p>
</div>
</div>

<div id="outline-container-orgb5ef25f" class="outline-2">
<h2 id="orgb5ef25f">16 Wrapup</h2>
<div class="outline-text-2" id="text-orgb5ef25f">
<p>
A summary of the topics discussed.
</p>

<video controls width="100%">
  <source src="/static/2020-05/16 Zusammenfassung.mp4" type="video/mp4">
</video>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> <a href="https://bastibe.de/tag-python.html">python</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <category><![CDATA[python]]></category>
  <link>https://bastibe.de/2020-05-14-file-parsing-tutorial.html</link>
  <guid>https://bastibe.de/2020-05-14-file-parsing-tutorial.html</guid>
  <pubDate>Thu, 14 May 2020 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[RAW Developer Comparison]]></title>
  <description><![CDATA[
<p>
It bit me again: I got software envy. <i>What if</i> I could develop my pictures faster with a different RAW developer? <i>What if</i> they looked better than they do now? Questions like these keep me up at night.
</p>

<div id="outline-container-org4926201" class="outline-2">
<h2 id="org4926201">The Problem</h2>
<div class="outline-text-2" id="text-org4926201">
<p>
Choice. There are so many RAW developers out there. And they all have rabid fan bases, and apparently unique rendering. How to choose?
</p>

<p>
Here are my house rules:
</p>
<ul class="org-ul">
<li>Must run on Windows or Linux</li>
<li>Must run acceptably on my Surface tablet</li>
<li>Must run acceptably with files on a network share</li>
<li>Must support my past and present cameras (Fuji X-E3, Ricoh GR, Pentax Q7, Nikon D7000)</li>
</ul>

<p>
In contrast to most other comparisons on the 'net<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>, I won't concern myself too much with sharpness and noise reduction and demosaicing. I have yet to see a photograph that was ruined by them, and most RAW developers seem to do a sufficient job at them.
</p>

<p>
I would prefer a file-based workflow with edits stored alongside the RAW files<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup>, and I would prefer a perpetual license instead of a rental contract, but I'm willing to compromize on both if it's worth it<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup>.
</p>

<p>
Obviously, I am a lot more proficient in my current tool, Darktable, than in any of the others. But for this test, I'm explicitly not doing anything particularly artistic; merely some highlight recovery, shadow recovery, and local white balance adjustments. By limiting myself to these edits, I hope to get an unbiased idea of the various RAW developer's implementations, without needing to ask the endless “what if” of what <i>else</i> I could have done. That said, I will leave all other adjustments on their default settings, to still get an impression of the general look of the programs.
</p>
</div>
</div>

<div id="outline-container-orgefcfe3b" class="outline-2">
<h2 id="orgefcfe3b">The Contestants</h2>
<div class="outline-text-2" id="text-orgefcfe3b">
<ul class="org-ul">
<li>Darktable 3.0.2 (<a href="https://www.darktable.org/">Free</a>) <br>
Free, works on Linux, very familiar to me. Allegedly, not particularly fast, with a confusing user interface.</li>
<li>Adobe Lightroom Classic CC 7.5 (<a href="https://www.adobe.com/products/photoshop-lightroom.html">$10/month</a>) <br>
Probably the most widespread tool. Somehow unappealing to me. Currently only available at a subscription price, but there is a “free” version available through my university.</li>
<li>Capture One 20.0.4 (<a href="https://www.captureone.com/">$29/month or $350</a>) <br>
Enormously expensive, even with the educational discount. Allegedly the best default color rendition, particularly for Fuji cameras.</li>
<li>RawTherapee 5.8 (<a href="http://rawtherapee.com/">Free</a>) <br>
Free, works on Linux. Allegedly extremely high image quality, but no local adjustments whatsoever.</li>
<li>Luminar 4.2.0 (<a href="https://skylum.com/luminar">$90</a>) <br>
A rather new developer, with fancy AI features such as automatic sky replacements. Not exactly what I'm looking for, but we'll see about its “normal” RAW development chops.</li>
<li>ON1 Photo RAW 2020.1 (<a href="https://www.on1.com/">$100</a>) <br>
Another highly regarded developer with rather traditional tools. This one works straight on files in the file system, though, which is highly attractive to me.</li>
<li>ACDSee Photo Studio Ultimate 2020 13.0 (<a href="https://www.acdsee.com/">$9/month or $150</a>) <br>
Wasn't this a fancy image viewer a few years ago? Apparently it's now a RAW developer.</li>
<li>Exposure X5 5.2.1.211 (<a href="https://exposure.software/">$120</a>) <br>
Allegedly super fast, with great sharpening and noise removal.</li>
<li>Photo Ninja 1.3.7a (<a href="https://www.picturecode.com/index.php">$130</a>) <br>
Another new developer, borne out of a dedicated noise reduction tool, and with an emphasis on “intelligent” tools.</li>
<li>Silkypix Developer Studio Pro 10.0.3.0 (<a href="https://silkypix.isl.co.jp/en/">$200</a>) <br>
A Japanese RAW developer. I wasn't aware of it until a comment brought it up, thank you for that! And I mention its country of origin, as the English translation is a bit rough sometimes. Quite unusual in its feature set.</li>
<li>Zoner Photo Studio X 19.2103.2.317 (<a href="https://www.zoner.com/">$50/year</a>) <br>
A somewhat unknown RAW developer. So much so that I only stumbled upon it one year after the original article. A true Windows-only product that feels at home in Windows like none of the other programs in this list.</li>
<li>DXO Photolab (<a href="https://www.dxo.com/dxo-photolab/">$220</a>) <br>
For the longest time, did not support Fuji X-Trans files. But this has changed in version 5, and I am eager to try it out!</li>
</ul>

<p>
Not considered:
</p>
<ul class="org-ul">
<li>Aftershot (<a href="https://www.aftershotpro.com/">$80</a>) <br>
Works on Linux, but doesn't support my Fuji camera because it hasn't been updated in ages.</li>
<li>Iridient Developer, Raw Power, Aperture <br>
Mac only</li>
<li>Affinity Photo (<a href="https://affinity.serif.com/">$55</a>) <br>
Cheap, awesome, but not non-destructive. I'll probably buy this regardless in a sale, just because it's so affordable.</li>
</ul>

<p>
In terms of price, it is hard to argue with <i>free</i>. But considering the price of my other photographic equipment, most prices in this list are pretty adequate. Except for Capture One (and maybe Silkypix). $350 ($200) is a hard price to swallow.
</p>
</div>
</div>


<div id="outline-container-orge7a3ddc" class="outline-2">
<h2 id="orge7a3ddc">The Test</h2>
<div class="outline-text-2" id="text-orge7a3ddc">
<p>
I prepared 18 RAW images for this test, and made a plan of what exactly I would do with every one of them. Then I developed them all in each of the RAW editors. I will only show excerpts here, both to keep private the pictures I don't want to share, and to keep this already long post from exploding.
</p>

<p>
Also, I mostly show difficult files here that have some obvious challenge. This is because I am usually quite satisfied with my cameras' JPEGs in easy cases, and don't bother with RAW development.
</p>
</div>

<div id="outline-container-org59f6ded" class="outline-3">
<h3 id="org59f6ded">Highlight Recovery</h3>
<div class="outline-text-3" id="text-org59f6ded">
<br>
  <div class="lightbox" style="height: 200px">
    <figure>
      <img src="/static/2020-05/DSCF3861.thumb.jpg">
      <figcaption>Camera</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/ACDSee_DSCF3861.thumb.jpg">
      <figcaption>ACDSee</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/CaptureOne_DSCF3861.thumb.jpg">
      <figcaption>Capture One</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Darktable_DSCF3861.thumb.jpg">
      <figcaption>Darktable</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Exposure_DSCF3861.thumb.jpg">
      <figcaption>Exposure</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Lightroom_DSCF3861.thumb.jpg">
      <figcaption>Lightroom</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Luminar_DSCF3861.thumb.jpg">
      <figcaption>Luminar</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/ON1_DSCF3861.thumb.jpg">
      <figcaption>ON1</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/PhotoNinja_DSCF3861.thumb.jpg">
      <figcaption>PhotoNinja</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/RawTherapee_DSCF3861.thumb.jpg">
      <figcaption>RawTherapee</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Silkypix_DSCF3861.thumb.jpg">
      <figcaption>Silkypix</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Zoner_DSCF3861.thumb.jpg">
      <figcaption>Zoner</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/DxO_DSCF3861.thumb.jpg">
      <figcaption>DxO</figcaption>
    </figure>
  </div>
<p><a href="/static/2020-05/DSCF3861.RAF">&#x1f4c2; DSCF3861.RAF</a> (23.0 MB) <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/80x15.png" /></a></p>

<p>
A shot of the sunset in Greece, with both the sun and its reflection in the water blowing out. I want to lower the highlights, and boost the shadows a bit. The transition from sky to sun should be smooth without lightness reversals or rings. The transition from water to reflection should have no color cast. The hills in the background should not show any halos.
</p>

<p>
Capture One, Lightroom, and DxO show the smallest sun without artifacts. RawTherapee, Darktable, ACDSee, Silkypix and Zoner produce a smooth transition, but a bigger sun. In Luminar, Exposure, Photo Ninja, and ON1 the sun is smaller, but has a distinct ring around it that looks wrong. In RawTherapee the sun is big and slightly ringed. Actually, Capture One and Silkypix also have a ring, but so faint that it wouldn't matter to me.
</p>

<p>
The reflections in the water are artifact-free in Darktable, Lightroom, Exposure, RawTherapee, and Zoner. The other developers show magenta artifacts to varying degrees, and DxO has some false-color pixels (their X-Trans support is still in beta). In terms of detail, Capture One, Lightroom, DxO, and Exposure recover a bit more wave details in the blown-out reflections.
</p>

<p>
The hills in the background show distracting halos in Capture One, Lightroom, and Exposure.
</p>

<p>
In the following list, the RAW developer name links to the sidecar file, if there is one:
</p>

<ul class="org-ul">
<li>Camera: Dynamic Range 400</li>
<li>ACDSee: Highlights 100, Fill Light 25</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF3861.RAF.xmp">Darktable</a>: My Defaults, Filmic RGB to shift dynamic range to include highlights, Highlight Reconstruction LCh and lower until magenta halo disappears</li>
<li>Capture One: Highlight and White -100, Shadow +20</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF3861.RAF.exposurex5">Exposure</a>: Highlights -100, Whites -50, Shadows +50 (less Whites desaturates)</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF3861.xmp">Lightroom</a>: Highlight -100, Shadow +50</li>
<li>Luminar: Highlights -100, Whites -50, Shadows +25</li>
<li><a href="https://bastibe.de/static/2020-05/DSF3861.on1">ON1</a>: Highlights -50, Shadows +25 (More Highlights produce lightness reversals)</li>
<li>Photo Ninja: Illumination 27, Exposure offset -1.62, Highlights -0.50 (all chosen automatically)</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF3861.RAF.pp3">RawTherapee</a>: Highlight Compression 250, Highlights 100, Shadows 25</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF3861.RAF.10.spd">Silkypix</a>: Highlight Dynamic Range +3, Hue 100</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF3861.RAF.data-zps">Zoner</a>: Lights -50, Shadows 25</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF3861.RAF.dop">DxO</a>: Highlights -100, Shadows 25</li>
</ul>

<p>
While a bit of a pathological image, there are clear differences in how these RAW developers handle it. Really, only Darktable, DxO and Lightroom produce a truly pleasing image for me, with second place to Capture One, ON1, and Silkypix. Surprisingly, the camera's own JPEG is amongst the best renditions as well.
</p>

<p>
Silkypix deserves a special mention, though, as its highlight control tool has a fantastic Hue slider, which trades off higher saturation against more accurate hue. Which is exactly the tradeoff that underlies all the rings and magenta artifacts in all the other programs.
</p>

<p>
On a side note, I have never quite understood why nobody seems to complain about the obvious haloing in Lightroom. I see it in almost every high dynamic range landscape shot on the internet, and I do not enjoy the look. But apparently I'm alone with this.
</p>
</div>
</div>

<div id="outline-container-org3620915" class="outline-3">
<h3 id="org3620915">Dynamic Range Reduction</h3>
<div class="outline-text-3" id="text-org3620915">
<br>
  <div class="lightbox" style="height: 200px">
    <figure>
      <img src="/static/2020-05/DSCF6535.thumb.jpg">
      <figcaption>Camera</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/ACDSee_DSCF6535.thumb.jpg">
      <figcaption>ACDSee</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/CaptureOne_DSCF6535.thumb.jpg">
      <figcaption>Capture One</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Darktable_DSCF6535.thumb.jpg">
      <figcaption>Darktable</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Exposure_DSCF6535.thumb.jpg">
      <figcaption>Exposure</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Lightroom_DSCF6535.thumb.jpg">
      <figcaption>Lightroom</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Luminar_DSCF6535.thumb.jpg">
      <figcaption>Luminar</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/ON1_DSCF6535.thumb.jpg">
      <figcaption>ON1</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/PhotoNinja_DSCF6535.thumb.jpg">
      <figcaption>PhotoNinja</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/RawTherapee_DSCF6535.thumb.jpg">
      <figcaption>RawTherapee</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Silkypix_DSCF6535.thumb.jpg">
      <figcaption>Silkypix</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Zoner_DSCF6535.thumb.jpg">
      <figcaption>Zoner</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/DxO_DSCF6535.thumb.jpg">
      <figcaption>DxO</figcaption>
    </figure>
  </div>
<p><a href="/static/2020-05/DSCF6535.RAF">&#x1f4c2; DSCF6535.RAF</a> (21.6 MB) <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/80x15.png" /></a></p>

<p>
A shot of a very contrasty forest scene at Mt. Washington, with highlights slightly blowing out, and shadows close to drowning. I want to lower highlights and raise shadows, without it looking crushed or unrealistic.
</p>

<p>
The most important thing in this picture is to maintain a realistic progression of tones, even though the dynamic range is crushed beyond reason. To my eyes, Lightroom really stands out here, with a three-dimensional look that no other developer can match. ACDSee, Darktable, ON1, Photo Ninja, and RawTherapee come second, with a believable progression. Exposure, Luminar, and Capture One seemingly applied some kind of local contrast compression that destroys the balance between highlights and shadows and flattens the image.
</p>

<p>
All developers show magenta artifacts on the bright forest floor to some degrees. They are particularly unpleasant in Capture One, Darktable, ACDSee, and Exposure.
</p>

<ul class="org-ul">
<li>ACDSee: Highlights 100, Fill Light 25</li>
<li>Capture One: Highlights -50, Shadows +25, Black +50</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF6535.RAF.xmp">Darktable</a>: My Defaults, Filmic RGB to expand dynamic range</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF6535.RAF.exposurex5">Exposure</a>: Highlights -100, Shadows +50, Blacks +25 (Blacks and Shadows interact weirdly)</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF6535.xmp">Lightroom</a>: Highlights -75, Shadows +50, Blacks +50</li>
<li>Luminar: Highlights -100, Whites -50, Shadows +50, Blacks +50</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF6535.on1">ON1</a>: Highlights -75, Shadows +50 (disable Recover Highlight Hue to prevent color fringes)</li>
<li>Photo Ninja: Illumination 25, Exposure offset -1.47, Highlights -0.50 (all chosen automatically)</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF6535.RAF.pp3">RawTherapee</a>: Highlights 50, Shadows 25, Dynamic Range Compression 50</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF6535.RAF.10.spd">Silkypix</a>: HDR 50, Exposure -2/3</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF6535.RAF.data-zps">Zoner</a>: Lights -75, Shadows 25, HDR Lights 25%, HDR Shadows 10%</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF6535.RAF.dop">DxO</a>: Highlights -75, Shadows 25, Blacks 10</li>
</ul>

<p>
In terms of tools, I like the explicit dynamic range slider in Darktable, RawTherapee, and Silkypix better than the shadows and highlights sliders in the other tools. But if calibrated well, both methods can result in a pleasing image.
</p>

<p>
To my eyes, Lightroom, DxO, RawTherapee, Photo Ninja, and Zoner take the crown in this shot. But I expect that the tone progression could be improved in the other tools as well if I strayed beyond the default tools.
</p>
</div>
</div>

<div id="outline-container-orgf878552" class="outline-3">
<h3 id="orgf878552">Local White Balance</h3>
<div class="outline-text-3" id="text-orgf878552">
<br>
  <div class="lightbox" style="height: 200px">
    <figure>
      <img src="/static/2020-05/DSCF8214.thumb.jpg">
      <figcaption>Camera</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/ACDSee_DSCF8214.thumb.jpg">
      <figcaption>ACDSee</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/CaptureOne_DSCF8214.thumb.jpg">
      <figcaption>Capture One</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Darktable_DSCF8214.thumb.jpg">
      <figcaption>Darktable</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Exposure_DSCF8214.thumb.jpg">
      <figcaption>Exposure</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Lightroom_DSCF8214.thumb.jpg">
      <figcaption>Lightroom</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Luminar_DSCF8214.thumb.jpg">
      <figcaption>Luminar</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/ON1_DSCF8214.thumb.jpg">
      <figcaption>ON1</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/PhotoNinja_DSCF8214.thumb.jpg">
      <figcaption>PhotoNinja</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/RawTherapee_DSCF8214.thumb.jpg">
      <figcaption>RawTherapee</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Silkypix_DSCF8214.thumb.jpg">
      <figcaption>Silkypix</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Zoner_DSCF8214.thumb.jpg">
      <figcaption>Zoner</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/DxO_DSCF8214.thumb.jpg">
      <figcaption>DxO</figcaption>
    </figure>
  </div>
<p><a href="/static/2020-05/DSCF8214.RAF">&#x1f4c2; DSCF8214.RAF</a> (22.1 MB) <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/80x15.png" /></a></p>

<p>
A shot of myself, underexposed, in front of Space Shuttle Enterprise. I want to brighten myself and adjust the white balance on my body so it matches the rest of the room. (I have better examples than this, but they showed people other than me, which I don't share.)
</p>

<p>
Photo Ninja, and RawTherapee fail this test, as they lack local adjustment tools. Exposure for some reason shows terrible color bleeding, where my arm's color is leaking out onto the Space Shuttle in the background. Truly noteworthy is ACDSee with its intelligent brush, much like the intelligent selection tools in pixel editors. Darktable als stands out for being able to combine a drawn mask with a luminosity and hue mask.
</p>

<p>
Capture One strangely did something terrible to my skin, with weird gradients where there should be none. The Shuttle in the background lost details in the highlights in ACDSee and Exposure and Zoner. DxO has various ways of drawing masks. In this case I used control points, but none of them worked particularly well. I expect that they would need some practice to use well. Silkypix by default insisted on crazy noise reduction that turned the picture into a watercolor. Thankfully that is easy to turn down.
</p>

<ul class="org-ul">
<li>ACDSee: Fill Light 50, Develop Brush with WB -50 (no picker)</li>
<li>Capture One: Shadows +50, Black +75, Drawn Layer with White Balance picker on Backpack</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF8214.RAF.xmp">Darktable</a>: My Defaults, Filmic RGB to shift dynamic range to include shadows, Luminosity and Painted mask with Color Balance picker</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF8214.RAF.exposurex5">Exposure</a>: Shadows +100, Blacks +25, Layer with Color Temperature lowered (no picker)</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF8214.xmp">Lightroom</a>: Shadows +100, Local Adjustment with WB -14 (no picker)</li>
<li>Luminar: Shadows +50, Local Adjustments with WB -46, Tint -6, Shadows 100</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF8214.on1">ON1</a>: Shadows +50, Local Adjustment with WB -18 and Tint +4 (no picker)</li>
<li>Photo Ninja: Illumination 25, Exposure offset -1.61, Highlights -0.50 (all chosen automatically), Shadows +0.50, No local adjustments available</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF8214.RAF.pp3">RawTherapee</a>: Shadows 50, No local adjustments</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF8214.RAF.10.spd">Silkypix</a>: Dodge HDR 50, Noise Reduction Smoothness 25, Partial Correction with Hue 130, Saturation 0.37</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF8214.RAF.data-zps">Zoner</a>: Shadows 50, Black 10, Local Adjustments with Shadows 30, Saturation -10, and Blue/Green pushed in Tone Curve (no picker)</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF8214.RAF.dop">DxO</a>: Shadows 25, Black 25, Local Adjustments with lowered WB, Shadows 25</li>
</ul>

<p>
I find local color adjustments my main use for localized edits. Having a color picker for that is very useful, but only available in Capture One, Darktable, and Luminar. In the other tools, I had to either eyeball it, or manually adjust tones until the RGB values read grey.
</p>

<p>
Thus, it is Lightroom, ON1, and Darktable that pass this test.
</p>
</div>
</div>

<div id="outline-container-org6f603c1" class="outline-3">
<h3 id="org6f603c1">Out of Gamut Colors</h3>
<div class="outline-text-3" id="text-org6f603c1">
<br>
  <div class="lightbox" style="height: 200px">
    <figure>
      <img src="/static/2020-05/DSCF0034.thumb.jpg">
      <figcaption>Camera</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/ACDSee_DSCF0034.thumb.jpg">
      <figcaption>ACDSee</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/CaptureOne_DSCF0034.thumb.jpg">
      <figcaption>Capture One</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Darktable_DSCF0034.thumb.jpg">
      <figcaption>Darktable</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Exposure_DSCF0034.thumb.jpg">
      <figcaption>Exposure</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Lightroom_DSCF0034.thumb.jpg">
      <figcaption>Lightroom</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Luminar_DSCF0034.thumb.jpg">
      <figcaption>Luminar</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/ON1_DSCF0034.thumb.jpg">
      <figcaption>ON1</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/PhotoNinja_DSCF0034.thumb.jpg">
      <figcaption>PhotoNinja</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/RawTherapee_DSCF0034.thumb.jpg">
      <figcaption>RawTherapee</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Silkypix_DSCF0034.thumb.jpg">
      <figcaption>Silkypix</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Zoner_DSCF0034.thumb.jpg">
      <figcaption>Zoner</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/DxO_DSCF0034.thumb.jpg">
      <figcaption>DxO</figcaption>
    </figure>
  </div>
<p><a href="/static/2020-05/DSCF0034.RAF">&#x1f4c2; DSCF0034.RAF</a> (15.7 MB) <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/80x15.png" /></a></p>

<p>
A shot of the Congress building in Leipzig, with a bright purple light that blows out the red color channel, which is wildly out of gamut of any reasonable color space. I want to see how the RAW developers deal with out-of-gamut colors. I raise Exposure by 1 EV, then push shadows until the clouds become faintly visible.
</p>

<p>
ACDSee, ON1, Photo Ninja, and RawTherapee fail this task, with obvious magenta or blue artifacts on the illuminated water jet. The other developers use various methods of inpainting, which look particularly convincing in Capture One, Lightroom, Silkypix, Luminar, DxO, and Zoner. Exposure and Darktable look less realistic, but acceptable in a pinch. Again, Silkypix' hue slider is very handy.
</p>

<ul class="org-ul">
<li>ACDSee: Fill Light 50, Exposure +1</li>
<li>Capture One: Black +75, Exposure +1</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF0034.RAF.xmp">Darktable</a>: My Defaults, Filmic RGB</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF0034.RAF.exposurex5">Exposure</a>: Blacks +50, Exposure +1</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF0034.xmp">Lightroom</a>: Shadows +100, Exposure +1</li>
<li>Luminar: Shadows +25, Exposure +1</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF0034.on1">ON1</a>: Shadows +50, Exposure +1</li>
<li>Photo Ninja: Illumination 9, Highlights -0.50 (all chosen automatically), Exposure offset 0.0</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF0034.RAF.pp3">RawTherapee</a>: Shadows 50, Exposure +1 (Highlight Reconstruction: Blend)</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF0034.RAF.10.spd">Silkypix</a>: Dodge HDR 100, Noise reduction Smoothness 25, Highlight Hue 100</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF0034.RAF.data-zps">Zoner</a>: Exposure 1.0, HDR Shadows 25%</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF0034.RAF.dop">DxO</a>: Exposure 1.0, Shadows 75, Midtones -100</li>
</ul>

<p>
I know the Darktable devs are actively working on improving this. In truth, Darktable would have failed this task just a few months ago. Issues like these also often happen with deep-blue flowers, which turn purple in the failing developers but maintain hue in the better ones.
</p>
</div>
</div>

<div id="outline-container-orgf0d3a1a" class="outline-3">
<h3 id="orgf0d3a1a">Color Rendition and Detail</h3>
<div class="outline-text-3" id="text-orgf0d3a1a">
<br>
  <div class="lightbox" style="height: 200px">
    <figure>
      <img src="/static/2020-05/DSCF9670.thumb.jpg">
      <figcaption>Camera</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/ACDSee_DSCF9670.thumb.jpg">
      <figcaption>ACDSee</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/CaptureOne_DSCF9670.thumb.jpg">
      <figcaption>Capture One</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Darktable_DSCF9670.thumb.jpg">
      <figcaption>Darktable</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Exposure_DSCF9670.thumb.jpg">
      <figcaption>Exposure</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Lightroom_DSCF9670.thumb.jpg">
      <figcaption>Lightroom</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Luminar_DSCF9670.thumb.jpg">
      <figcaption>Luminar</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/ON1_DSCF9670.thumb.jpg">
      <figcaption>ON1</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/PhotoNinja_DSCF9670.thumb.jpg">
      <figcaption>PhotoNinja</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/RawTherapee_DSCF9670.thumb.jpg">
      <figcaption>RawTherapee</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Silkypix_DSCF9670.thumb.jpg">
      <figcaption>Silkypix</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/Zoner_DSCF9670.thumb.jpg">
      <figcaption>Zoner</figcaption>
    </figure>
    <figure>
      <img src="/static/2020-05/DxO_DSCF9670.thumb.jpg">
      <figcaption>DxO</figcaption>
    </figure>
  </div>
<p><a href="/static/2020-05/DSCF9670.RAF">&#x1f4c2; DSCF9670.RAF</a> (25.7 MB) <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/80x15.png" /></a>
</p>

<p>
A shot of a field and forest. I want to see how the RAW developers render these details and colors. Zero out noise reduction, use default sharpening, JPEG 100%.
</p>

<p>
In terms of detail, Lightroom, Capture One, Exposure, Silkypix, Zoner, DxO, and Darktable seem to retain the most fine details, particularly in the little trees and the forest floor. ACDSee, Luminar, RawTherapee, Photo Ninja, and ON1 look comparatively soft or lose detail in the shadows. Silkypix, however, has a strange, painterly look to the grass details that I wasn't able to get rid of.
</p>

<p>
In terms of overall color, Exposure, Photo Ninja, RawTherapee, and Capture One clearly tend towards the most saturated look, with a clear distinction between a green and a yellow part in the field. I suspect that these try to approximate the punchy look of Fuji's colors. These color transitions are much more subtle in ACDSee, Darktable, Exposure, Lightroom, Luminar, Silkypix, Zoner, DxO, and ON1. The sky is distinctly blue in Darktable, Photo Ninja, DxO, and Luminar, more cyan in ACDSee, Lightroom, and Silkypix, and weirdly purple in Capture One and RawTherapee.
</p>

<ul class="org-ul">
<li>ACDSee: Amount 25</li>
<li>Capture One: Amount 140</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF9670.RAF.xmp">Darktable</a>: My Defaults, Sharpen 2</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF9670.RAF.exposurex5">Exposure</a>: Amount 50</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF9670.xmp">Lightroom</a>: Amount 40</li>
<li>Luminar: Details Enhancer, Sharpen 50</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF9670.on1">ON1</a>: Sharpening 50</li>
<li>Photo Ninja: Sharpening strength 50</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF9670.RAF.pp3">RawTherapee</a>: Sharpening 20</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF9670.RAF.10.spd">Silkypix</a>: Zero Noise reduction, Outline emphasis 30, Ringing artifact control 15 (defaults)</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF9670.RAF.data-zps">Zoner</a>: Sharpening strength 150 (Smart Sharpen)</li>
<li><a href="https://bastibe.de/static/2020-05/DSCF9670.RAF.dop">DxO</a>: Lens Sharpness Global 1.0</li>
</ul>

<p>
I would not put too much emphasis on the colors, saturation, and contrast here, as these are easily and typically adjusted manually. I am a bit surprised about the differences in detail retention, however.
</p>
</div>
</div>
</div>


<div id="outline-container-org3ba3295" class="outline-2">
<h2 id="org3ba3295">The Result</h2>
<div class="outline-text-2" id="text-org3ba3295">
<p>
I went into this expecting to find Lightroom and Capture One to be vastly faster in use than Darktable, particularly on my Surface tablet. I also expected better out-of-the-box image beauty, large differences in user interfaces, and for most tools to have very few graphical artifacts. Surprisingly, however, almost every tool showed obvious artifacts of one kind or another, and few tools were actually faster than Darktable. In terms of tools, I found most tools look very similar, yet function vastly differently.
</p>

<br>
<div class="lightbox" style="height: 200px">
  <figure>
    <img src="/static/2020-05/ACDSee_exposure.png">
    <figcaption>ACDSee</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/CaptureOne_exposure.png">
    <figcaption>CaptureOne</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/Darktable_exposure.png">
    <figcaption>Darktable</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/Exposure_exposure.png">
    <figcaption>Exposure</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/Lightroom_exposure.png">
    <figcaption>Lightroom</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/Luminar_exposure.png">
    <figcaption>Luminar</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/ON1_exposure.png">
    <figcaption>ON1</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/PhotoNinja_exposure.png">
    <figcaption>PhotoNinja</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/RawTherapee_exposure.png">
    <figcaption>RawTherapee</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/Silkypix_exposure.png">
    <figcaption>Silkypix</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/Zoner_exposure.png">
    <figcaption>Zoner</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/DxO_exposure.png">
    <figcaption>DxO</figcaption>
  </figure>
</div>
<br>

<p>
Simple saturation and contrast adjustments, a bit of local contrast, and rarely some dodging and burning or local color adjustments are apparently all I do most of the time, and this generally works well and similarly in all of these tools. However, that is not to say that the individual sliders do remotely the same thing in different tools. So confused was I by this that I measured the response curves of several tools, and they indeed did entirely different things. In one tool, <i>Highlights</i> pushes the upper half of the tone curve. In another, even the darkest shadows are affected a little bit. In yet another, <i>Highlights</i> burns out to the upper quarter of the tone curve if pushed all the way. Sometimes the white point stays white, sometimes it moves. Sometimes it only moves if the slider is pushed past half-way. And that's not even taking into account their different blending behavior and value scales; these sliders may look the same, but there hides complexity beyond measure.
</p>

<br>
<div class="lightbox" style="height: 200px">
  <figure>
    <img src="/static/2020-05/ACDSee_color.png">
    <figcaption>ACDSee</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/CaptureOne_color.png">
    <figcaption>CaptureOne</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/Darktable_color.png">
    <figcaption>Darktable</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/Exposure_color.png">
    <figcaption>Exposure</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/Lightroom_color.png">
    <figcaption>Lightroom</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/Luminar_color.png">
    <figcaption>Luminar</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/ON1_color.png">
    <figcaption>ON1</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/PhotoNinja_color.png">
    <figcaption>PhotoNinja</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/RawTherapee_color.png">
    <figcaption>RawTherapee</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/Silkypix_color.png">
    <figcaption>Silkypix</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/Zoner_color.png">
    <figcaption>Zoner</figcaption>
  </figure>
  <figure>
    <img src="/static/2020-05/DxO_color.png">
    <figcaption>DxO</figcaption>
  </figure>
</div>
<br>

<p>
And I did find a surprising amount of graphical artifacts in these programs, particularly the color bleeding in Exposure, and the highlight recovery problems in Luminar and ON1, as well as a number of smaller issues. The one program that truly stands out here is Lightroom, which is more robust to artifacts than any other tool in this list, seemingly due to some significant image-adaptive intelligence under the hood.
</p>

<p>
I have strong mixed feelings about Capture One. On the one hand, it has one of the most attractive user interfaces of all these tools. On the other, its color renditions are very opinionated, and not my favorite. I love how it reads and applies Fuji color profiles as shot, but then it doesn't apply the Fuji shadow/highlight adjustments and crushes the shadows unnecessarily. And while its color tools sure look nice, their functionality is not that much different than the other developers', and they are spread out needlessly across several tabs. And that price.
</p>

<p>
Playing around with Luminar was deeply impressive. There are a ton of magic and automatic features in there. But as cool as AI sky replacement is, it simply has no place in my toolbelt, and the general speed of the UI are a big minus.
</p>

<p>
I like ON1. It's relatively affordable, works with simple JSON sidecar files instead of a library, has reasonable tools, and impressive effects. It can even mimic the look of the embedded JPEG and supports Fuji film simulations. Not quite on the graphical level as Capture One or Lightroom, but very close. And it even runs acceptably fast on my Surface tablet.
</p>

<p>
Exposure is another program I could like a lot, but the color bleeding and graphical artifacts are just not up to snuff. In one example, it entirely failed to guess colors from an underexposed bar scene (not shown). In another it bled colors out onto adjacent objects for no reason. And white balance sometimes changed lightness as well as colors. I read that this might be a graphics driver issue, but regardless, it shook my confidence in Exposure.
</p>

<p>
ACDSee was a real surprise to me. I seem to remember it as a fast image viewer, but apparently it is (now?) an impressive RAW editor as well. There is a lot to like about this tool. The magic brush for local adjustments is a particularly noteworthy touch, as well as very robust healing tools. Alas, I found the UI rather slow, and it failed on exporting a few files. I'll try again in a year or so.
</p>

<p>
I was only made aware of Silkypix through a comment after the post had already been published (thank you!). And what I read on the website made me quite excited! Its tools stray somewhat from the Lightroom-inspired norm, which is a very good thing in some cases, such as the hue-priority highlight recovery. It also works on plain files, and seems to have outstanding Fuji film simulations. Alas, it was very slow to use, and not suitable for my Surface tablet.
</p>

<p>
I had tried RawTherapee a few times in the past, and was always frustrated by its lack of local adjustments, and the need to view things at 100% to see some adjustments. On the other hand, it can match the embedded JPEG tones, and has quite a number of impressive algorithms. Still, it does not appeal to me. But it's still an amazing achievement and a pretty inspiring community as well.
</p>

<p>
Photo Ninja is a curious program. Certainly not because of its ease of use, or speed of operation, or image quality. But because it did most things almost correctly automatically. That's not what I am looking for, but it is truly impressive.
</p>

<p>
I only discovered Zoner Photo about a year after this post was originally published. But I was impressed by what I found: It is a well-designed program with a solid array of tools, even including a pixel editor. And rather affordable, too. Curiously, Zoner Photo does not officially support some of my cameras, but can utilize the free Adobe DNG converter to make them readable on the fly, without creating a separate copy. Smart!
</p>

<p>
DxO PhotoLabs was another latecomer, which only started supporting Fuji X-Trans files in late 2021. I downloaded it on the day it became available, and was duly impressed. Its tools are less streamlined than in other programs, but seem to be of great algorithmic quality; there was hardly a lightness reversal or halo to be found, the bane of many a cheaper product. I am deeply intrigued.
</p>

<p>
And Lightroom. As I said, I somehow do not like Lightroom. Maybe because I like to be “different”, or because I associate Adobe too much with bloated software. But I have to say, Lightroom surprised me. While its tools are sometimes in weird locations, it is highly streamlined for a very fast workflow, and it deserves my highest praise for being outstandingly robust against artifacts. But I still don't like it.
</p>

<p>
Which leaves Darktable. This is a tool I am deeply familiar with, and have used for several years. Yet until this day, I never realized just how <i>strange</i> its tools are compared to the other programs. How weird Filmic RGB must feel if you are used to shadows and highlights sliders, and how alien the graph-based color zones and tone equalizer and contrast equalizer must seem.
</p>

<br>
<div class="lightbox" style="height: 200px">
  <img src="/static/2020-05/Darktable_exposure.png">
  <img src="/static/2020-05/Darktable_color.png">
  <img src="/static/2020-05/Darktable_color_zones.png">
  <img src="/static/2020-05/Darktable_contrast_equalizer.png">
  <img src="/static/2020-05/Darktable_tone_equalizer.png">
</div>
<br>

<p>
Yet, in direct comparison, I find Darktable's tools equally efficient at solving problems, even if the solutions are sometimes a bit different from its Lightroom-inspired peers. One tool in particular I want to emphasize: Color Zones. At first glance, it looks like your standard HSL tool that allows brightness, saturation, and hue changes by color (albeit as a graph instead of sliders). But then you discover the “select-by” switch, and realize that you can modify colors by lightness and saturation, as well as hue. I use this frequently to saturate shadows, which is a great effect I haven't seen in any other program.
</p>

<p>
No doubt other programs have cool features, too, but Darktable (and RawTherapee) seem uniquely open about their inner workings. And this brings joy to me, on a level the closed, artistic programs can't match. I <i>like</i> graphs, and maths. I'm weird like that.
</p>

<p>
But what really prompted this whole comparison blog post was my frustration with Darktable's speed. Particularly on my 4K screen, it is not the fastest program out there. And the AMD/OpenCL situation on Linux is still a travesty, which doesn't help. But I learned a thing during this experiment: You must work bottom-up through the rendering chain, if you want Darktable to be fast<sup><a id="fnr.4" class="footref" href="#fn.4" role="doc-backlink">4</a></sup>. Which, in my case, usually means working through <i>Lens Correction</i> → <i>Crop and Rotate</i> → <i>Exposure</i> → <i>Tone Equalizer</i> → <i>Contrast Equalizer</i> → <i>Color Balance</i> → <i>Filmic RGB</i> → <i>Color Zones</i>. As long as I (mostly) edit things in this order, Darktable is fast enough, even on my Surface tablet.
</p>

<p>
Lastly, I have to say a few words about file management. Most programs here work on some kind of local library that stores all edits. The downside of this is that these libraries are hard to sync between computers, are hard to back up, and need to manually be kept in sync when file locations change. Notable exceptions here are Lightroom, Darktable, Exposure<sup><a id="fnr.5" class="footref" href="#fn.5" role="doc-backlink">5</a></sup>, Silkypix<sup><a id="fnr.5.100" class="footref" href="#fn.5" role="doc-backlink">5</a></sup>, RawTherapee, ON1, DxO, and Zoner, which keep their edits alongside the RAW files in little text “sidecar” files<sup><a id="fnr.6" class="footref" href="#fn.6" role="doc-backlink">6</a></sup>. Thus even if their library goes out of sync or is lost, at least the edits are still there. To be honest, this is quite an important factor for me.
</p>

<p>
As for library management, my requirements are small: I want to filter by date, rating, and maybe camera or lens. These needs are met by all programs except possibly Luminar and Photo Ninja. I do most of my file management in external programs on camera import, and with the exported JPEGs, so this area of the RAW developers is not very important to me.
</p>

<p>
However, this comparison also highlighted just how useful sidecar files are to photo management. I might choose different RAW developers over the years, and my photo management solutions might change over time as well. But as long as all edits are stored in simple text files next to the RAW file, I can rest safe in the knowledge that my edits will never be lost. This is a serious downside to ACDSee, Capture One, Luminar, and Photo Ninja, who keep edits secretly<sup><a id="fnr.7" class="footref" href="#fn.7" role="doc-backlink">7</a></sup> in their opaque databases.
</p>

<p>
I also timed my work with every one of these programs. Quite surprisingly, I couldn't find any significant differences between programs. Darktable's workflows, for example, are sometimes entirely different from other tools; but if you know what you're doing the path from identifying a problem to fixing it is still similarly straight-forward and fast. And there is no less experimentation until I arrive at a look I like.
</p>

<p>
Thus, I am left with Darktable, Lightroom, and ON1. And theoretically Capture One, but that price is just too high for me. If Capture One were $100 instead of $350, I would probably switch to it. Even educational pricing is only available for rentals. I'll have to decline that. And despite all my praise for Lightroom, I still don't like it.
</p>

<p>
I'll probably buy ON1 at its current, discounted price ($50), and see how I like it in actual daily use<sup><a id="fnr.8" class="footref" href="#fn.8" role="doc-backlink">8</a></sup>. But at the same time. I'll also stick with Darktable on my Linux machine, at least for more complicated edits. I now know that Darktable can dance with the best of them, which is mighty impressive for a piece of free software.
</p>

<p>
With all that said and done, I have learned a lot about RAW development during this experiment. Regardless of which tool I end up sticking with, this has been a fascinating comparison. We'll see how long I can resist the urge to compare this time.
</p>

<p>
<b>Addendum: Customer Support</b>
</p>

<p>
So far, I have been in contact with the Customer Support people of ON1, Capture One, and Zoner. And I must say, ON1 and Zoner were incredibly pleasant and quick and helpful, while Capture One seemed almost reluctant to help. This is actually a big plus for ON1 and Zoner, and kind of big turnoff for Capture One.
</p>

<p>
<b>Update: Silkypix</b>
</p>

<p>
I added Silkypix to the comparison, thanks to kind comments underneath this post.
</p>

<p>
<b>Update: Luminar Local Adjustments</b>
</p>

<p>
I was made aware that Luminar does indeed have local adjustments, they were merely in such an uncommon place that I hadn't found the initially.
</p>

<p>
<b>Update: Zoner Photo</b>
</p>

<p>
One year after the original post, I added Zoner Photo to the comparison.
</p>

<p>
<b>Update: DxO PhotoLab</b>
</p>

<p>
One-and-a-half years after the original post, DxO Photo Labs added support for Fuji files, so I added them to the comparison.
</p>
</div>
</div>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
There are surprisingly few non-superficial comparisons; most are just feature matrix comparisons. The best ones I could find are a fantastic, in-depth comparison on <a href="http://www.nomadlens.com/raw-converters-comparison">nomadlens</a>, A Fuji-centric discussion of detail extraction on <a href="https://www.fujivsfuji.com/best-xtrans-raw-converter">Fuji vs. Fuji</a>, one by <a href="https://www.andybellphotography.com/blog/2018/06/23/raw-converter-shootout-part-1/">Andy Bell</a> that might be sponsored/biased by Luminar, a pretty good one on <a href="https://petapixel.com/2018/03/01/raw-processors-compared-theres-lot-image-quality/">PetaPixel</a>, an older one on <a href="https://www.dpreview.com/articles/8219582047/raw-converter-showdown-capture-one-pro-7-dxo-optics-pro-8-and-lightroom-4">DPReview</a>, and a Nikon-centered one on <a href="https://wypictures.wordpress.com/2015/08/07/comparison-of-raw-converters-for-nikon/">WY Pictures</a>.
</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">Makes it much easier to share edits between computers, and back them up</p></div></div>

<div class="footdef"><sup><a id="fn.3" class="footnum" href="#fnr.3" role="doc-backlink">3</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">I don't like rental software, as it locks away all past edits once I stop paying.</p></div></div>

<div class="footdef"><sup><a id="fn.4" class="footnum" href="#fnr.4" role="doc-backlink">4</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">because lower stages in the pipeline are cached, but higher stages need to be recalculated after every edit.</p></div></div>

<div class="footdef"><sup><a id="fn.5" class="footnum" href="#fnr.5" role="doc-backlink">5</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">in an unnecessary subdirectory</p></div></div>

<div class="footdef"><sup><a id="fn.6" class="footnum" href="#fnr.6" role="doc-backlink">6</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">Capture One saves sidecar files, too, but only for metadata, not edits</p></div></div>

<div class="footdef"><sup><a id="fn.7" class="footnum" href="#fnr.7" role="doc-backlink">7</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">They would say, "securely"</p></div></div>

<div class="footdef"><sup><a id="fn.8" class="footnum" href="#fnr.8" role="doc-backlink">8</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">not really daily, but you know what I mean</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2020-05-01-raw-developer-comparison.html</link>
  <guid>https://bastibe.de/2020-05-01-raw-developer-comparison.html</guid>
  <pubDate>Fri, 01 May 2020 19:15:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[The Value Proposition of Open Source Software]]></title>
  <description><![CDATA[
<p>
To <a href="https://en.wikipedia.org/wiki/Open-source_software">quote Wikipedia</a>:
</p>

<blockquote>
<p>
Open Source Open-source software (OSS) is a type of computer software in which source code is released under a license in which the copyright holder grants users the rights to study, change, and distribute the software to anyone and for any purpose.
</p>
</blockquote>

<p>
In practice, this generally means software developed by hobbyists in their free time, as opposed to professionals at a company.
</p>

<p>
But why should such software be preferable to commercial products? I shall ignore price, for the moment. While open source software generally does not cost money, I have no qualms about paying money for software, and can easily afford to, as well. So if it's not price, what then?
</p>

<p>
Richard Stallman makes an argument that it's <a href="https://www.gnu.org/philosophy/open-source-misses-the-point.html">all about Freedom</a>. But I have a suspicion that he really wants the <i>code</i> to be free, not its users<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>. He argues that "free" licenses make the program's source code available to users. Presumably, to read it and change it. However, I don't do that, generally. And neither do I redistribute software, which is another "freedom" granted by Stallman-style free software. Also, <a href="https://discourse.ardour.org/t/is-open-source-a-diversion-from-what-users-really-want/102665">you don't need access to the source code to change a software</a>. But I still prefer Open Source Software to commercial software, in most cases.
</p>

<p>
And the reason is, that in my experience, Open Source Software is generally better software. And I believe the reason for this is incentives:
</p>

<p>
Open Source Software is generally created to scratch an itch. One single developer was sufficiently disgruntled to throw all caution into the wind, and solve the problem him/herself. Which means that at least one person was dissatisfied with the commercial offerings at the time.
</p>

<p>
And there are plenty of reasons to be dissatisfied with commercial software. Commercial software needs to make money. And to justify recurring sales, it must keep adding features, often beyond the usefulness to users. Thus, big changes and new features are incentivized, while continued refinement and bug fixing are merely cost centers.
</p>

<p>
Contrast this with Open Source Software, which is quite content to simply <i>work</i>. No new features need to be added if the software is complete as it is, and no new effort needs to be invested if there aren't any bugs remaining. Such software is a joy to use.
</p>

<p>
In the commercial world, such software is not <i>stable</i>, but <i>stagnant</i>. A sign of death, not maturity. And when commercial software dies, it is buried, never to be used again. And all the work its users have created with it over the years, <a href="https://en.wikipedia.org/wiki/Aperture_(software)">becomes inaccessible and obsolete with it</a>. In the same way, today's online-only subscription-based software distributions are essentially protection rackets that require a monthly ransom just to keep access to your existing work. The moment you stop paying, all your previous work becomes inaccessible. Such moves are indeed Stallman-worthy invasions of freedom that are unacceptable to me<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup>.
</p>

<p>
Of course, Open Source Software allows users to contribute to the product. But In my own projects, I have found this to vary greatly between cultures. Some communities seem to be naturally tinker-friendly, such as <a href="https://github.com/bastibe/org-journal">Emacs</a> or <a href="https://github.com/darktable-org/darktable">Darktable</a>. Others, such as <a href="https://github.com/bastibe/SoundCard">Python's</a> or <a href="https://github.com/bastibe/Violinplot-Matlab">Matlab's</a>, are strangely reluctant to help one another, with more users creating bug reports than contributors creating pull requests.
</p>

<p>
Funny enough, price does not enter this equation. Because what you need to use Open Source Software is often not money, but time. And only rich people have that. If you're poor, and paying for software is a problem, you're far more likely to pirate "professional" software with a known value proposition, than to spend time on an unknown quantity. Open Source Software is a <a href="https://discuss.pixls.us/t/darktable-user-survey/16824">toy for the rich</a>, and paradoxically unattractive to people in need<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup>.
</p>

<p>
So in summary, I have generally found Open Source Software to be <i>better</i> than commercial software in most circumstances. Perhaps as a next step, we should try to figure out how to get payed for creating it, and how to keep monetary incentives from ruining products.
</p>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">See <a href="https://louigiverona.com/?page=projects&amp;s=writings&amp;t=philosophy&amp;a=philosophy_freedoms">this link</a> for an exhaustive discussion of that topic. It's an amazing article!</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">Except for video games, which I only consume once, and which result in experiences, not artifacts. Strange, how this distinction is surprisingly hard to justify.</p></div></div>

<div class="footdef"><sup><a id="fn.3" class="footnum" href="#fnr.3" role="doc-backlink">3</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">User-facing software, that is. Linux web servers are for everyone</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> <a href="https://bastibe.de/tag-open-source.html">open-source</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <category><![CDATA[open-source]]></category>
  <link>https://bastibe.de/2020-03-27-the-value-proposition-of-open-source-software.html</link>
  <guid>https://bastibe.de/2020-03-27-the-value-proposition-of-open-source-software.html</guid>
  <pubDate>Fri, 27 Mar 2020 08:17:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Qt for Python Video Tutorial]]></title>
  <description><![CDATA[
<p>
This video series was produced in the spring of 2020, during the COVID19-pandemic, when all lectures had to be held electronically, without physical attendance. It is a tutorial, in German, for building a small Qt GUI that visualizes the ongoing pandemic on a world map.
</p>

<p>
If the videos are too slow, feel free to speed them up by right-clicking, and adjusting play speed (Firefox only, as far as I know).
</p>

<p>
You may also download the videos and share them with your friends. Please do not upload them to social media or YouTube, but link to this website instead. If you want to modify them or create derivative works, please contact me.
</p>

<center>
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-nd/4.0/88x31.png" /></a><br />The <span xmlns:dct="http://purl.org/dc/terms/" href="http://purl.org/dc/dcmitype/MovingImage" property="dct:title" rel="dct:type">Qt for Python Video Tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://bastibe.de/2020-03-20-qt-for-python-tutorial.html" property="cc:attributionName" rel="cc:attributionURL">Bastian Bechtold</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/">Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License</a>.
</center>

<p>
<b><b>Update:</b></b> As of April 2022, all code examples have been updated to use PySide6. In particular, this changes the imports, replaces <code>app.exec_()</code> with <code>app.exec()</code>, and replaces <code>mouseEvent.pos()</code> with <code>mouseEvent.position().toPoint()</code> (see note in <a href="https://bastibe.de/static/2020-03/map11.py">map11.py</a>:).
</p>

<div id="outline-container-orgf0b5a25" class="outline-2">
<h2 id="orgf0b5a25">1 Intro</h2>
<div class="outline-text-2" id="text-orgf0b5a25">
<p>
Prerequisites: A basic understanding of Python, and a working installation of python ≥3.4.
</p>

<p>
An overview over the topics discussed in the rest of the videos, and installation of <a href="https://www.qt.io/qt-for-python">Qt for Python</a> and <a href="https://pandas.pydata.org/">Pandas</a>.
</p>

<video controls width="100%">
  <source src="/static/2020-03/01 intro.mp4" type="video/mp4">
</video>
</div>
</div>

<div id="outline-container-org9362a57" class="outline-2">
<h2 id="org9362a57">2 Hello World</h2>
<div class="outline-text-2" id="text-org9362a57">
<p>
Our first GUI program, a window with a text label.
</p>

<video controls width="100%">
  <source src="/static/2020-03/02 hello world.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map2.py">map2.py</a></p>
</div>
</div>


<div id="outline-container-orgb94b122" class="outline-2">
<h2 id="orgb94b122">3 Main Window</h2>
<div class="outline-text-2" id="text-orgb94b122">
<p>
Create a <a href="https://doc.qt.io/qtforpython/PySide2/QtWidgets/QMainWindow.html">QMainWindow</a>, and build some structure for later episodes.
</p>

<video controls width="100%">
  <source src="/static/2020-03/03 main window.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map3.py">map3.py</a></p>
</div>
</div>

<div id="outline-container-org44792f7" class="outline-2">
<h2 id="org44792f7">4 Layouts</h2>
<div class="outline-text-2" id="text-org44792f7">
<p>
Position a <a href="https://doc.qt.io/qtforpython/PySide2/QtWidgets/QLabel.html">QLabel</a> and a <a href="https://doc.qt.io/qtforpython/PySide2/QtWidgets/QPushButton.html">QPushButton</a> side by side, using layouts.
</p>

<video controls width="100%">
  <source src="/static/2020-03/04 layouts.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map4.py">map4.py</a></p>
</div>
</div>


<div id="outline-container-org5968f9f" class="outline-2">
<h2 id="org5968f9f">5 Signals and Slots</h2>
<div class="outline-text-2" id="text-org5968f9f">
<p>
Make the button change the label's text if clicked.
</p>

<video controls width="100%">
  <source src="/static/2020-03/05 signals and slots.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map5.py">map5.py</a></p>
</div>
</div>


<div id="outline-container-org664e5c4" class="outline-2">
<h2 id="org664e5c4">6 Loading Data</h2>
<div class="outline-text-2" id="text-org664e5c4">
<p>
Load the data required to draw a map.
</p>

<video controls width="100%">
  <source src="/static/2020-03/06 loading data.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map6.py">map6.py</a></p>
<p>Data: <a href="/static/2020-03/countries_110m.json">countries_110m.json</a></p>
</div>
</div>


<div id="outline-container-org4045783" class="outline-2">
<h2 id="org4045783">7 Drawing the Map</h2>
<div class="outline-text-2" id="text-org4045783">
<p>
Draw a world map into a <a href="https://doc.qt.io/qtforpython/PySide2/QtWidgets/QGraphicsScene.html">QGraphicsScene</a>.
</p>

<video controls width="100%">
  <source src="/static/2020-03/07 drawing the map.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map7.py">map7.py</a></p>
</div>
</div>


<div id="outline-container-org9d3219b" class="outline-2">
<h2 id="org9d3219b">8 Pens and Brushes</h2>
<div class="outline-text-2" id="text-org9d3219b">
<p>
Make the map pretty, using <a href="https://doc.qt.io/qtforpython/PySide2/QtGui/QPen.html">QPens</a> and <a href="https://doc.qt.io/qtforpython/PySide2/QtGui/QBrush.html">QBrushes</a>.
</p>

<video controls width="100%">
  <source src="/static/2020-03/08 pens and brushes.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map8.py">map8.py</a></p>
</div>
</div>


<div id="outline-container-org6c5afa7" class="outline-2">
<h2 id="org6c5afa7">9 Resize Event</h2>
<div class="outline-text-2" id="text-org6c5afa7">
<p>
Resize the map when the window size changes, by overloading <a href="https://doc.qt.io/qtforpython/PySide2/QtWidgets/QWidget.html#PySide2.QtWidgets.PySide2.QtWidgets.QWidget.resizeEvent"><code>resizeEvent</code></a>.
</p>

<video controls width="100%">
  <source src="/static/2020-03/09 resize event.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map9.py">map9.py</a></p>
</div>
</div>


<div id="outline-container-orgad238fe" class="outline-2">
<h2 id="orgad238fe">10 Mouse Tracking</h2>
<div class="outline-text-2" id="text-orgad238fe">
<p>
Highlight the country under the mouse.
</p>

<video controls width="100%">
  <source src="/static/2020-03/10 mouse tracking.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map10.py">map10.py</a></p>
</div>
</div>


<div id="outline-container-org6720d81" class="outline-2">
<h2 id="org6720d81">11 Custom Signal</h2>
<div class="outline-text-2" id="text-org6720d81">
<p>
Respond to clicks of a country.
</p>

<video controls width="100%">
  <source src="/static/2020-03/11 custom signal.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map11.py">map11.py</a></p>
</div>
</div>


<div id="outline-container-orgcdee6a1" class="outline-2">
<h2 id="orgcdee6a1">12 Addendum</h2>
<div class="outline-text-2" id="text-orgcdee6a1">
<p>
Improve the code by cutting out a middle man.
</p>

<video controls width="100%">
  <source src="/static/2020-03/12 addendum.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map12.py">map12.py</a></p>
</div>
</div>


<div id="outline-container-orge71b788" class="outline-2">
<h2 id="orge71b788">13 Pandas</h2>
<div class="outline-text-2" id="text-orge71b788">
<p>
A quick introduction to <a href="https://pandas.pydata.org/">Pandas</a>.
</p>

<video controls width="100%">
  <source src="/static/2020-03/13 pandas.mp4" type="video/mp4">
</video>
<p>Data: <a href="/static/2020-03/covid19.csv">covid19.csv</a></p>
</div>
</div>


<div id="outline-container-org3b450c6" class="outline-2">
<h2 id="org3b450c6">14 Pandas Integration</h2>
<div class="outline-text-2" id="text-org3b450c6">
<p>
Load the COVID19 dataset and print some stats.
</p>

<video controls width="100%">
  <source src="/static/2020-03/14 pandas integration.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map14.py">map14.py</a></p>
</div>
</div>


<div id="outline-container-org041fa4e" class="outline-2">
<h2 id="org041fa4e">15 Model View Tables</h2>
<div class="outline-text-2" id="text-org041fa4e">
<p>
Display the COVID19 dataset in a <a href="https://doc.qt.io/qtforpython/PySide2/QtWidgets/QTableView.html">QTableView</a>.
</p>

<video controls width="100%">
  <source src="/static/2020-03/15 model view tables.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map15.py">map15.py</a></p>
</div>
</div>


<div id="outline-container-org8f3eb4f" class="outline-2">
<h2 id="org8f3eb4f">16 Table Header Data</h2>
<div class="outline-text-2" id="text-org8f3eb4f">
<p>
Fill in the table headers from the dataset.
</p>

<video controls width="100%">
  <source src="/static/2020-03/16 header data.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map16.py">map16.py</a></p>
</div>
</div>


<div id="outline-container-org819f503" class="outline-2">
<h2 id="org819f503">17 Country Selection</h2>
<div class="outline-text-2" id="text-org819f503">
<p>
Show only a subset of the dataset when a country is clicked.
</p>

<video controls width="100%">
  <source src="/static/2020-03/17 country selection.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map17.py">map17.py</a></p>
</div>
</div>


<div id="outline-container-orgbfc773e" class="outline-2">
<h2 id="orgbfc773e">18 Cleanup</h2>
<div class="outline-text-2" id="text-orgbfc773e">
<p>
Summary, and a few finishing touches.
</p>

<video controls width="100%">
  <source src="/static/2020-03/18 cleanup.mp4" type="video/mp4">
</video>
<p>Code: <a href="/static/2020-03/map18.py">map18.py</a></p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> <a href="https://bastibe.de/tag-python.html">python</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <category><![CDATA[python]]></category>
  <link>https://bastibe.de/2020-03-20-qt-for-python-tutorial.html</link>
  <guid>https://bastibe.de/2020-03-20-qt-for-python-tutorial.html</guid>
  <pubDate>Fri, 20 Mar 2020 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Books of 2019]]></title>
  <description><![CDATA[

<div id="outline-container-orgc444b85" class="outline-2">
<h2 id="orgc444b85"><a href="https://www.goodreads.com/book/show/23692271-sapiens">Sapiens</a></h2>
<div class="outline-text-2" id="text-orgc444b85">

<figure id="org1839dc0">
<img src="https://bastibe.de/static/2020-03/sapiens-cover.jpg" alt="sapiens-cover.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<p>
More than any other book this year, <i>Sapiens</i> changed my view of the world. Or at least that's what it felt like while reading. It seemed as if every page contained a new and mind-blowing shift in perspective, such as casting money, democracy, and capitalism as "religions", and questioning the value of civilization in terms of individual human experience. My mind was reeling from the implications of these viewpoints, in a very good way.
</p>

<p>
On the other hand, my memory of the book is marred by the author's second book, <i>Homo Deus</i>, which highlights just how little the author's knowledge of history is worth when extrapolating into the future. It is, essentially, boring and shallow science fiction, with seemingly no knowledge decades of previous writing on the topic.
</p>

<p>
Come to think about it, this might reveal more about me than the author, for my own expertise is clearly more in science fiction than history; I might simply be much easier to please in the latter than in the former.
</p>
</div>
</div>

<div id="outline-container-org5f53c3c" class="outline-2">
<h2 id="org5f53c3c"><a href="https://www.goodreads.com/book/show/785625.The_Boat_Who_Wouldn_t_Float">The Boat Who Wouldn't Float</a></h2>
<div class="outline-text-2" id="text-org5f53c3c">

<figure id="org1cadf74">
<img src="https://bastibe.de/static/2020-03/the-boat-who-wouldnt-float-cover.jpg" alt="the-boat-who-wouldnt-float-cover.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<p>
This is the partly-fictional account of the author, Mowat Farley, and his boat. That leeks. And stinks. And doesn't sail well. And that is still entirely endearing.
</p>

<p>
Or maybe it is really about the humor with which the author recounts his misadventures on the Canadian shore. I stuck with this book even though my terrible digital library loaner had whole corrupted pages every chapter or two. But I could neither put it down, nor stop laughing. This might be the funniest book I have read in a decade. I must read more Mowat Farley!
</p>
</div>
</div>

<div id="outline-container-orgfe2412a" class="outline-2">
<h2 id="orgfe2412a"><a href="https://www.goodreads.com/series/160439-the-machineries-of-empire">Ninefox Gambit / Raven Stratagem / Revenant Gun</a></h2>
<div class="outline-text-2" id="text-orgfe2412a">

<figure id="orgd4dc868">
<img src="https://bastibe.de/static/2020-03/ninefox-gambit-cover.jpg" alt="ninefox-gambit-cover.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<p>
I did not like the first book in this series. It had a certain spark, but there was so much jargon and confusion, I just couldn't keep up. Yet. I kept coming back to it. That spark.
</p>

<p>
And in 2019, I bit the bullet, and picked up the sequel. And as with many things in life, it was better the second time around. Even though I still didn't quite get this particular sciency-fantasy-space-opera thing; I now felt at home in it, and could enjoy the story unraveling before me. At which point I couldn't put it down any longer. The <i>two weeks</i> I had to wait after finishing the second book before the third one released were harrowing. A masterpiece!
</p>
</div>
</div>

<div id="outline-container-orgeb3bd5f" class="outline-2">
<h2 id="orgeb3bd5f"><a href="https://www.goodreads.com/series/191900-the-murderbot-diaries">The Murderbot Diaries</a></h2>
<div class="outline-text-2" id="text-orgeb3bd5f">

<figure id="org0b2c8b6">
<img src="https://bastibe.de/static/2020-03/murderbot-cover.jpg" alt="murderbot-cover.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<p>
Sometimes I don't want to think. Sometimes I like a simple bit of escapism, like chocolate. Sometimes, I need to read about the Murderbot.
</p>

<p>
I love how the Murderbot Diaries cast humanity as uncaring and somewhat dim animals, with the most humane characters invariably being artificial intelligences. And the character of Murderbot itself is just so plain delightful, how it simultaneously wants to get away from, yet deeply cares for, us silly, childish humans.
</p>
</div>
</div>

<div id="outline-container-org8205a9b" class="outline-2">
<h2 id="org8205a9b"><a href="https://www.goodreads.com/book/show/19537969-brains-bullets">Brains vs. Bullets</a></h2>
<div class="outline-text-2" id="text-org8205a9b">

<figure id="orgbcd8ccb">
<img src="https://bastibe.de/static/2020-03/brains-vs-bullets-cover.jpg" alt="brains-vs-bullets-cover.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<p>
This is an odd one. It's about soldiers, and how they fight. Or rather, what keeps them from fighting. Because every one has a breaking point, and soldiers are often quite close to it when they fight.
</p>

<p>
And as it turns out, humans are by and large pretty bad at killing each other. Even professional soldiers apparently are often unable to do so, despite years of training and propaganda. Which is a heartening message indeed, for a book on warfare.
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-books.html">books</a> ]]></description>
  <category><![CDATA[books]]></category>
  <link>https://bastibe.de/2020-03-11-books-of-2019.html</link>
  <guid>https://bastibe.de/2020-03-11-books-of-2019.html</guid>
  <pubDate>Wed, 11 Mar 2020 17:08:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Editing Fuji Photos on Linux]]></title>
  <description><![CDATA[
<p>
Darktable is my favorite RAW editor. It's a program for developing digital negatives ("RAW files") to JPEGs. But, I've long struggled with matching the quality of the out-of-camera JPEGs of my Fuji camera. Let me explain.
</p>

<p>
Today's cameras capture an astounding amount of detail, far more than monitors can display or printers can print. And then they crush it down to a printable and viewable JPEG file. But that crushing operation is idiomatic for each camera, irreversible, and not always appropriate to the image. And at those inappropriate times, when you want a wider dynamic range or different colors, a RAW editor like Darktable can take a digital sensor dump ("RAW file"), and render it differently. The challenge is that the camera's own JPEGs are already very, very good, and it's a fine line to walk between fixing a particular flaw with the image, while retaining as much detail as possible.
</p>

<p>
Fuji cameras produce notoriously difficult RAW files, as their internal processing is (said to be) particularly elaborate, and they use an <a href="https://en.wikipedia.org/wiki/Fujifilm_X-Trans_sensor">unusual image sensor</a>. This post is about matching the quality of Fuji's JPEGs in Darktable, while maintaining the fidelity and malleability of the RAW files.
</p>

<p>
Here are a few renditions of a photograph I took, the first created with my revised process, the second is Fuji's JPEG, and the third is Darktable's default rendition. First the entire picture, the a zoomed view so you can see each pixel:
</p>

<br>
<a href="/static/2020-02/darktable-lightbox.html" target="_blank">
  <div class="lightbox" style="height: 200px">
    <img src="/static/2020-02/mine_full.thumb.jpg">
    <img src="/static/2020-02/fuji_full.thumb.jpg">
    <img src="/static/2020-02/dt_full.thumb.jpg">
    <img src="/static/2020-02/mine_100.thumb.jpg">
    <img src="/static/2020-02/fuji_100.thumb.jpg">
    <img src="/static/2020-02/dt_100.thumb.jpg">
  </div>
</a>
<br>

<p>
While contrast and saturation don't match 100% in my version and Fuji's, the colors are close enough for further processing. Darktable's default version does not match those colors at all. The zoomed-in version highlights even worse problems with sharpness and detail retention. After working with Fuji files in Darktable for about a year, and editing about 3500 Fuji files, I finally found a workflow that reliably produces results on par with Fuji's JPEGs:
</p>

<ol class="org-ol">
<li>Use the <a href="https://www.iridientdigital.com/products/xtransformer.html">Iridient X-Transformer</a> to convert Fuji's RAF RAW-files to DNG RAW-files, and have the X-Transformer do the "More Detailed" demosaicing, and the full lens correction.</li>
<li>Use <a href="https://blog.sowerby.me/fuji-film-simulation-profiles/">Stuart Sowerby's LUTs</a> instead of Darktable's Base Curve or Filmic RGB.</li>
</ol>

<p>
My first gripe with Darktable's rendering of Fuji files is that the demosaicing and lens corrections are not particularly great. Pictures simply come out softer than with other tools, and chromatic aberrations remain an issue. The Iridient X-Transformer completely fixes this issue for me. The X-Transformer can also do sharpening and denoising, but I find those are better relegated to Darktable where needed. "But&#x2026; that's proprietary Windows software!!!". Yes, it is. And it works beautifully in Wine.
</p>

<p>
My second issue is colors. Darktable needs a lot of massaging to produce Fuji-like colors. The Base Curve module (shown above) really does not do Fuji files justice most of the time. And while Filmic RGB is much better, it requires a lot of tedious adjustments even in simple cases. So instead, I use LUTs extracted with a color chart and some fancy math to replicate Fuji's colors. At the moment (v3.0), Darktable understands only .cube and .png LUTs. But Stuart Sowerby's website has them in .3dl. So for now, you need to install a <a href="https://grossgrade.com/en/2019/08/14/batch-3d-lut-converter/">3D LUT converter</a>, and convert them to .cube manually. On Windows.
</p>

<p>
With these two steps you can develop your Fuji RAFs better than your camera, and with relatively little fuss. I'll leave you with a finished render of the image above:
</p>


<figure id="orge33cbbe">
<img src="https://bastibe.de/static/2020-02/mine.jpg" alt="mine.jpg">

</figure>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> <a href="https://bastibe.de/tag-linux.html">linux</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <category><![CDATA[linux]]></category>
  <link>https://bastibe.de/2020-02-09-editing-fuji-photos-on-linux.html</link>
  <guid>https://bastibe.de/2020-02-09-editing-fuji-photos-on-linux.html</guid>
  <pubDate>Sun, 09 Feb 2020 12:54:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[I Miss My Mac]]></title>
  <description><![CDATA[
<p>
There was a time, maybe from 2009 to 2011, when Apple computers were glorious. They were elegant devices, beautiful to me, and powerful. Never before, or since, have I loved a machine as I loved that MacBook Pro early 2011.
</p>

<p>
I miss that, being able to love the elegance and power a machine.
</p>

<p>
Nowadays I mostly use KDE Linux, which I can tolerate. Things occasionally break, stuff sometimes doesn't work as intended, but I can generally work around these quirks, so they don't bother me too much. Today, off the top of my head, Firefox crashed, Thunderbird couldn't display one folder, Zotero had to be re-installed, one monitor had to be power-cycled when waking the computer, and the laptop battery died way too quickly again.
</p>

<p>
I also use a Windows Surface tablet, which is a wonderful little device. It currently shows an error message every time it boots that I can't get rid of, has to be rebooted every few days to stay fast, and sometimes just won't react until restarted. And it always wants to install some update, and just refuses to do it overnight as intended. But generally it works pretty well.
</p>

<p>
And yesterday, in a bout of nostalgia, I opened my macOS laptop again and endeavored to write a bit on it. There were no updates, then there were updates but they couldn't be installed, then they could be installed, then the download stalled, and hat to be un-paused for some reason. Then my project files randomly couldn't be downloaded to the laptop, and the window management in macOS is a horrid mess. Also the update took a full hour, and didn't change anything noteworthy. I didn't end up actually getting to write on it.
</p>

<p>
In the evening, my camera corrupted its file system, as it sometimes does if I forget to format the SD card as FAT instead of its default exFAT. The recovery process was tedious but worked. I've done it a few times now and I know what to do.
</p>

<p>
My phone, meanwhile, can't use its fingerprint reader any longer ever since I "up"graded to Android 10. It's a Pixel 2, as google as Google can be. And apps are sometimes unresponsive and have to be restarted to become usable again. And it still can't undo text edits in the year 2020, and probably spies on my every move.
</p>

<p>
My amplifier nominally supports Bluetooth, but it only works some of the time. Currently it doesn't, so we use a portable Bluetooth speaker instead. Its Spotify integration has never worked even once. But at least it now reliably sends an image to the projector ever since we vowed to only ever touch the one reliable HDMI port on the front of it.
</p>

<p>
And as much as I love my ebook reader, it sometimes crashes when there's too much stuff on the page. One time I even had to completely reset it to get it to work again. And every time I install an update, the visual layout changes. Most of the time, mostly for the better. But it just erodes trust so much, to be at the mercy of the whims of an obviously demented software designer somewhere.
</p>

<p>
As I said, I miss my Mac, back when technology was magical, and just worked. And any error could be clearly explained as user error instead of terrible programming. When I was young and foolish, in other words.
</p>

<p>
I should go play with my child now, and run around in the yard, or maybe read a paper book. There's no joy in technology any more.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-computers.html">computers</a> <a href="https://bastibe.de/tag-macos.html">macos</a> ]]></description>
  <category><![CDATA[computers]]></category>
  <category><![CDATA[macos]]></category>
  <link>https://bastibe.de/2020-01-21-i-miss-my-mac.html</link>
  <guid>https://bastibe.de/2020-01-21-i-miss-my-mac.html</guid>
  <pubDate>Tue, 21 Jan 2020 16:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Efficiency is not Intuitive]]></title>
  <description><![CDATA[
<p>
A few days ago, a <a href="https://www.darktable.org/2019/12/darktable-30/">new version of Darktable</a> was released. Darktable is an Open Source RAW image processor, and one of my favorite pieces of software of all time. It may be THE most powerful RAW processor on the market, far exceeding its proprietary brothers. But in the social media discussions following the release, it got dismissed for being <i>unintuitive</i>.
</p>

<p>
Which is silly, ironic, sad; why should <i>Intuition</i> be a measure of quality for professional software? Because in contrast to a transient app on your phone, RAW processing is a complex task that requires months of study to do well. Like most nontrivial things, it is fundamentally not an intuitive process. In fact, most of my favorite tools are like this: <i>Efficient</i>, but not <i>Intuitive</i>; like Darktable, Scientific Python, the Unix Command Line, Emacs.
</p>

<p>
These tools empower me to do my job quickly and directly. They provide sharp tools for intelligent users, which can be composed easily and infinitely. Their power derives from clean metaphors and clear semantics, instead of "intuitive", "smart", magics. They require <i>learning</i> to use well, but reward that effort with efficiency. They are <i>professional</i>, and treat their users as adults.
</p>

<p>
In my career as a software developer, I know these ideas as traits of good APIs: Orthogonal, minimal, composable. APIs are great not when they are as expansive and convenient as possible, but when they are most constrained and recombinable. In other words, "don't optimize for stupid". That's what I understand as good design in both programming, and in professional UIs.
</p>

<p>
Which is quite the opposite of <i>Intuitive</i>. Quite the opposite of "easy to grasp without reading the manual". That's a description of a video game, not a professional tool. As professionals, we should seek and build empowering, efficient tools for adults, not intuitive games maskerading as professional software.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-computers.html">computers</a> <a href="https://bastibe.de/tag-ui.html">ui</a> ]]></description>
  <category><![CDATA[computers]]></category>
  <category><![CDATA[ui]]></category>
  <link>https://bastibe.de/2019-12-29-efficiency-is-not-intuitive.html</link>
  <guid>https://bastibe.de/2019-12-29-efficiency-is-not-intuitive.html</guid>
  <pubDate>Sun, 29 Dec 2019 12:06:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Travel Cameras]]></title>
  <description><![CDATA[
<p>
We went on a once-in-a-lifetime vacation this year. Six weeks in the USA, roving New England in an RV, and going on a helicopter tour around New York City. I have spent months thinking about the perfect camera for going on this trip. I went on several vacations with various permutations of cameras and lenses as a test-run. I data-mined my existing photographs to find the perfect setup through science. And I scoured the internet for untold hours to get it right.
</p>

<p>
Here's what I took with me:
</p>


<figure id="org99e604d">
<img src="https://bastibe.de/static/2019-10/P1020974_2.jpg" alt="P1020974_2.jpg">

<figcaption><span class="figure-number">Figure 1: </span>A Fuji X-E3 with an XF 18-135 lens, and a Ricoh GR</figcaption>
</figure>


<p>
That's <i>two</i> cameras! Most people would take <del>their smartphone</del> one camera with multiple lenses. I take multiple cameras with one lens each. Why? Because they're both awesome, at different things:
</p>

<div id="outline-container-org3cafda0" class="outline-2">
<h2 id="org3cafda0">The Fujifilm X-E3 with an XF 18-135 f/3.5-5.6 lens</h2>
<div class="outline-text-2" id="text-org3cafda0">
<p>
The X-E3 is a mirrorless camera, which means it's small. It is a very recent camera with a modern sensor. It's a rangefinder-style camera with the viewfinder in the top left. So it doesn't obscure my whole face when I lift it to my eye.
</p>

<p>
<a href="https://camerasize.com/compact/#721.426,7.175,ha,t">Compared to a DSLR</a>, this is a small and light camera<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>. But paired with the lens, it is neither. That lens, though: a massive focal range from 18 mm to 135 mm is suitable for wide landscapes, as well as tight tele shots of wildlife. Cramming it all in one lens must come with a loss in sharpness and aperture, but the 18-135 is a best of its breed, and still plenty sharp enough for me. And it comes with an image stabilization so sophisticated that I can hand-hold half-second exposures. Which is <i>magic</i>.
</p>


<figure id="orgd133992">
<img src="https://bastibe.de/static/2019-10/P1020982_2.jpg" alt="P1020982_2.jpg">

<figcaption><span class="figure-number">Figure 2: </span>The X-E3 with the lens extended. Small, it is not.</figcaption>
</figure>

<p>
This is a great camera for deliberately framing a shot; it feels great to hold, with a neat and efficient control layout for quickly playing with apertures and shutter speeds and focal lengths with a minimum amount of fuss. It is a dependable tool, an amazing piece of engineering, and an artistic means of expression. It is truly a great camera.
</p>

<p>
If it has an Achille's heel, it's that it takes a while to get ready. Not because it is slow to start up, but because there's a delay before the viewfinder activates when raised to the face. Which just means you will stare into the void for half a second, while seeing the critical moment pass in front of you. Half a second of missing the shot.
</p>

<p>
And the white balance can struggle a bit with forests and lakes. Forests are green, and to compensate, the X-E3 turns everything else magenta. Easy to fix in post, but annoying. These are minor complaints, and most of the time the X-E3 is as perfect a camera as I've ever seen one.
</p>

<p>
Here are a few pictures I took with the X-E3 on my last vacation<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup>:
</p>

<br>
<a href="/static/2019-10/fuji-lightbox.html" target="_blank">
  <div class="lightbox" style="height: 200px">
    <img src="/static/2019-10/DSCF5479_4.thumb.jpg">
    <img src="/static/2019-10/DSCF5734_4.thumb.jpg">
    <img src="/static/2019-10/DSCF5832_4.thumb.jpg">
    <img src="/static/2019-10/DSCF5864_4.thumb.jpg">
    <img src="/static/2019-10/DSCF6399_4.thumb.jpg">
    <img src="/static/2019-10/DSCF6485_4.thumb.jpg">
    <img src="/static/2019-10/DSCF6535_4.thumb.jpg">
    <img src="/static/2019-10/DSCF6599_4.thumb.jpg">
    <img src="/static/2019-10/DSCF6659_4.thumb.jpg">
    <img src="/static/2019-10/DSCF6750_4.thumb.jpg">
    <img src="/static/2019-10/DSCF6806_4.thumb.jpg">
    <img src="/static/2019-10/DSCF6891_4.thumb.jpg">
    <img src="/static/2019-10/DSCF6928_4.thumb.jpg">
    <img src="/static/2019-10/DSCF6960_4.thumb.jpg">
    <img src="/static/2019-10/DSCF7359_4.thumb.jpg">
    <img src="/static/2019-10/DSCF7512_4.thumb.jpg">
    <img src="/static/2019-10/DSCF7590_4.thumb.jpg">
    <img src="/static/2019-10/DSCF7694_4.thumb.jpg">
    <img src="/static/2019-10/DSCF7744_4.thumb.jpg">
    <img src="/static/2019-10/DSCF7807_4.thumb.jpg">
    <img src="/static/2019-10/DSCF8016_4.thumb.jpg">
    <img src="/static/2019-10/DSCF8076_4.thumb.jpg">
    <img src="/static/2019-10/DSCF8137_4.thumb.jpg">
  </div>
</a>
<br>

<p>
Image quality is simply excellent. Not once has the X-E3 let me down. Autofocus is accurate, and instant. The lens is amazingly sharp all through its focal range. Dynamic range is unreal, at times. As you can see in the pictures, I've shot everything from landscapes to people, to wildlife, long exposures, and even some astro. All with one lens, on one camera.
</p>
</div>
</div>

<div id="outline-container-orgbc59da4" class="outline-2">
<h2 id="orgbc59da4">The Ricoh GR</h2>
<div class="outline-text-2" id="text-orgbc59da4">
<p>
So, if the X-E3 is my "professional" camera, the Ricoh GR is my fun camera. In 2019, the GR old technology. It was released in 2013, it has a big but aging 16 megapixel APS-C sensor, and a fixed 18 mm f/2.8 lens with no zoom. It shouldn't be able to compete with the Fuji. But there is one thing the GR does better than any other camera: <i>Speed</i>.
</p>


<figure id="org3eb873b">
<img src="https://bastibe.de/static/2019-10/DSCF1333_3.jpg" alt="DSCF1333_3.jpg">

<figcaption><span class="figure-number">Figure 3: </span>The Ricoh GR in all its glory (before the vacation)</figcaption>
</figure>

<p>
The GR is in my pants pocket. It wouldn't be my pants without a GR in it. I have it with me everywhere, all the time. And at the right moment, I will pull it out, and take a picture, before you even notice it's there. That's the GR's mission: <i>The fastest possible time from pants to picture!</i>
</p>

<p>
Seriously, the GR goes from off to taking the first shot before even its screen turns on<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup>. I can whip out my GR and take a picture long before you have unlocked your phone, never mind started the camera app, selected a focus point, or aimed it at your prey. In the car, I had the GR in the center console, and could take a picture of the roadside before it whizzed past. And without taking my eyes off the road, naturally.
</p>

<p>
Since the GR has a fixed and wide focal length, I don't have to look at its screen to see what I'm taking a picture of. I can do it by feel. Because all the controls are on the right, I can adjust everything with my right hand only, without taking my hands off the wheel, or stroller, or wife. And then there's snap focus, where a full-press of the shutter will take a shot at a pre-defined distance, without waiting for autofocus. I wish every camera had this feature!
</p>

<p>
However, all of this took some getting used to at first. I missed focus a lot in the beginning. But once I figured it out, a new world opened up. A world of whimsy and spontaneity that is simply not possible with a bigger or slower camera. A good half of my favorite pictures were only possible thanks to the GR.
</p>


<figure id="orgb70c1d9">
<img src="https://bastibe.de/static/2019-10/DSCF9162_2.jpg" alt="DSCF9162_2.jpg">

<figcaption><span class="figure-number">Figure 4: </span>The Ricoh GR after the vacation: scarred, but stronger for it.</figcaption>
</figure>


<p>
Again, there are downsides. It's an old sensor. Dynamic range is limited. Autofocus could be faster. There's a noticeable shutter delay. There is no viewfinder or image stabilization. The white balance is not great. It can struggle with a full memory card<sup><a id="fnr.4" class="footref" href="#fn.4" role="doc-backlink">4</a></sup>.
</p>

<p>
But none of that matters. I <i>love</i> its colors. I <i>love</i> its sharpness. It has taken quite the beating on this vacation, but I wouldn't have it any other way. The GR is magnificent. There is nothing else quite like it<sup><a id="fnr.5" class="footref" href="#fn.5" role="doc-backlink">5</a></sup>. And so many memories would have been lost if not for the GR:
</p>

<br>
<a href="/static/2019-10/ricoh-lightbox.html" target="_blank">
  <div class="lightbox" style="height: 200px">
    <img src="/static/2019-10/GR030371_4.thumb.jpg">
    <img src="/static/2019-10/GR030471_4.thumb.jpg">
    <img src="/static/2019-10/GR030994_4.thumb.jpg">
    <img src="/static/2019-10/GR031668_4.thumb.jpg">
    <img src="/static/2019-10/GR031686_4.thumb.jpg">
    <img src="/static/2019-10/GR031800_4.thumb.jpg">
    <img src="/static/2019-10/GR031827_4.thumb.jpg">
    <img src="/static/2019-10/GR031878_4.thumb.jpg">
    <img src="/static/2019-10/GR031947_4.thumb.jpg">
    <img src="/static/2019-10/GR032078_4.thumb.jpg">
    <img src="/static/2019-10/GR032376_4.thumb.jpg">
    <img src="/static/2019-10/GR032380_4.thumb.jpg">
    <img src="/static/2019-10/GR032420_4.thumb.jpg">
    <img src="/static/2019-10/GR032551_4.thumb.jpg">
    <img src="/static/2019-10/GR032806_4.thumb.jpg">
    <img src="/static/2019-10/GR032887_4.thumb.jpg">
    <img src="/static/2019-10/GR033056_4.thumb.jpg">
    <img src="/static/2019-10/GR033178_4.thumb.jpg">
    <img src="/static/2019-10/GR033179_4.thumb.jpg">
    <img src="/static/2019-10/GR033248_4.thumb.jpg">
    <img src="/static/2019-10/GR033263_4.thumb.jpg">
  </div>
</a>
<br>

<p>
Many of these shots were taken in the spur of the moment. In situations where I didn't take the big camera with me. Where a big camera would have been inappropriate. But the GR is so tiny, so non-threatening, it can become part my daily life. And capture the fleeting moments that make life worth living. That is a photographic super power if there ever was one.
</p>
</div>
</div>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
The body weighs 337g, which is a feather. The lens weighs 490g.
</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
No personal pictures, though. I don't share those publicly.
</p></div></div>

<div class="footdef"><sup><a id="fn.3" class="footnum" href="#fnr.3" role="doc-backlink">3</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
The magic is "snap focus". If you depress the shutter fully, without waiting for autofocus, the GR immediately takes the shot at a pre-set distance. Works in any mode, and even when just powering on: Press the power button, aim, press the shutter, and before even the screen turns on you will have taken a picture. Lightning fast.
</p></div></div>

<div class="footdef"><sup><a id="fn.4" class="footnum" href="#fnr.4" role="doc-backlink">4</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
As the card fills up, getting into playback mode takes longer and longer. Minutes, for a full 64 Gb card.
</p></div></div>

<div class="footdef"><sup><a id="fn.5" class="footnum" href="#fnr.5" role="doc-backlink">5</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
Forget about the Fuji XF10. I tried it. It's a newer sensor, but so clumsy, so slow, so awkward to use. It's no comparison.
</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2019-10-27-travel-cameras.html</link>
  <guid>https://bastibe.de/2019-10-27-travel-cameras.html</guid>
  <pubDate>Sun, 27 Oct 2019 20:22:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Analyzing Speech Signals in Time and Frequency]]></title>
  <description><![CDATA[
<p>
Our first stop in speech analysis is usually the short-time Fourier transform, or STFT<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>:
</p>


<figure id="org54e6d3d">
<img src="https://bastibe.de/static/2019-09/stft.png" alt="stft.png">

<figcaption><span class="figure-number">Figure 1: </span>Top: an STFT of speech (it's me, saying: "Es war einmal ein Mann"). Bottom: the signal's waveform.</figcaption>
</figure>

<p>
As we can see, this speech signal has a strong fundamental frequency track around 120 Hz, and harmonics at integer multiples of the fundamental frequency. We perceive the frequency of the fundamental as the speech's pitch. The magnitude of the harmonics varies over time, which we perceive as the sounds of different vowels.
</p>

<p>
All of this is clearly visible in this STFT. To calculate the STFT, we chop up the audio signal into short, overlapping blocks, apply a <i>window function</i> <sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup> to each of these blocks, and Fourier-transform each windowed block into the frequency domain:
</p>


<figure id="org3034e77">
<img src="https://bastibe.de/static/2019-09/block-processing.png" alt="block-processing.png">

<figcaption><span class="figure-number">Figure 2: </span>The STFT is a two-dimensional graph of short-time spectra. Window functions and corresponding spectra of some blocks are highlighted.</figcaption>
</figure>

<p>
We zoomed in a bit to make this visible. At this zoom level, an <a href="https://bastibe.de/2019-09-19-periodicity-and-harmonicity.html">old friend</a> becomes visible in the waveform: The waveform of our harmonic spectra is clearly periodic. We also see that each of our blocks contain multiple periods of the speech signal. So what happens if we make our blocks shorter?
</p>


<figure id="org5c6c56d">
<img src="https://bastibe.de/static/2019-09/short-blocks.png" alt="short-blocks.png">

<figcaption><span class="figure-number">Figure 3: </span>STFT with shorter blocks (graph shows a shorter time, too). Each window now covers roughly one period of the signal.</figcaption>
</figure>

<p>
As we make our blocks shorter, such that they only contain a single period of the signal, a funny thing happens: the harmonic structure vanishes. Why? Because the harmonic structure is caused by the interference between neighboring clicks; As soon as each block is restricted to a single period, there is no interference any longer, and no harmonic structure.
</p>

<p>
But instead of a harmonic structure, we see the periodicity of the waveform emerge in the STFT! To look at this phenomenon in a bit more detail, we will have to leave the classical STFT domain, and look at a close sibling, the Constant Q Transform, or CQT. The CQT is simply an STFT with different block sizes for different frequencies:
</p>


<figure id="org24e6504">
<img src="https://bastibe.de/static/2019-09/cqt.png" alt="cqt.png">

<figcaption><span class="figure-number">Figure 4: </span>The CQT uses shorter block sizes for higher frequencies and longer block sizes for lower frequencies.</figcaption>
</figure>

<p>
The periodic structure of the signal is now perfectly apparent. Each period of the signal gives rise to a skewed click-like spectrum that repeats at the fundamental frequency. Interestingly, however, the fundamental itself shows no periodicity. To see why this is so, and to finally get a grasp of how the short-time Fourier transforms interprets signals, we have to turn to our last graph, a gamma-tone filterbank:
</p>


<figure id="org3151ed0">
<img src="https://bastibe.de/static/2019-09/gammatone.png" alt="gammatone.png">

<figcaption><span class="figure-number">Figure 5: </span>A gamma-tone filterbank is a series of band-pass filters. Each horizontal line is now a frequency-constrained waveform.</figcaption>
</figure>

<p>
The fundamental frequency is now clearly a visible as a single sinusoid, rotating its merry way at 120 Hz. Each harmonic is its own sinusoid at an integer multiple of the fundamental frequency, but changing in amplitude in lockstep with the findamental. Thus in this graph, we see both the harmonicity and the periodicity at the same time, and can finally appreciate the complex interplay of magnitudes and phases that give rise to the beautiful and simple sound of the human voice<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup>.
</p>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
also known as "spectrogram"
</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
a Hann window, in this case
</p></div></div>

<div class="footdef"><sup><a id="fn.3" class="footnum" href="#fnr.3" role="doc-backlink">3</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
in the magnitude domain only; Phases, and different window functions, go beyond the scope of this article.
</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-signal-processing.html">signal-processing</a> ]]></description>
  <category><![CDATA[signal-processing]]></category>
  <link>https://bastibe.de/2019-09-20-analyzing-speech-signals-in-time-and-frequency.html</link>
  <guid>https://bastibe.de/2019-09-20-analyzing-speech-signals-in-time-and-frequency.html</guid>
  <pubDate>Fri, 20 Sep 2019 09:40:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Periodicity and Harmonicity]]></title>
  <description><![CDATA[
<p>
A periodic signal has a harmonic spectrum. In the extreme case, a click train signal has a comb spectrum:
</p>


<figure id="org713372f">
<img src="https://bastibe.de/static/2019-09/comb.png" alt="comb.png">

<figcaption><span class="figure-number">Figure 1: </span>A click train (left), and its corresponding comb spectrum (right).</figcaption>
</figure>

<p>
But why? After all, a solitary click has a uniform spectrum. So why should the sum of multiple clicks have a non-uniform spectrum?
</p>


<figure id="orgf02c194">
<img src="https://bastibe.de/static/2019-09/click.png" alt="click.png">

<figcaption><span class="figure-number">Figure 2: </span>A click (left), and its corresponding spectrum (right).</figcaption>
</figure>

<p>
The answer exposes a lot of detail of how spectra work, and gives us a glimpse into the inner workings of spectral phases. Let's start with that click: In that spectrum, we see that we can decompose a click into a sum of sine waves:
</p>


<figure id="org5552b7c">
<img src="https://bastibe.de/static/2019-09/click_sum.png" alt="click_sum.png">

<figcaption><span class="figure-number">Figure 3: </span>A click (left), and its Fourier series (right). For simplicity, not all frequencies of the Fourier series are shown.</figcaption>
</figure>

<p>
As we have seen in the spectrum of the click earlier, it is composed of all frequencies (uniform spectrum). But we see here that the individual sine waves are delayed <i>just so</i>, that they all add constructively at exactly one time, and form the click. At all other times, they cancel each other out. This per-sine delay is called the phase of that frequency.
</p>

<p>
But what happens if we have more than one click? How does that change things?
</p>


<figure id="org8f68aa7">
<img src="https://bastibe.de/static/2019-09/click_train.png" alt="click_train.png">

<figcaption><span class="figure-number">Figure 4: </span>A click train (left), and its Fourier series (right). For simplicity, not all frequencies of the Fourier series are shown. The contributions of each click are shown in different colors.</figcaption>
</figure>

<p>
In a click train, odd frequencies in the Fourier series of the individual clicks cancel each other out (red/blue), and only harmonic frequencies (brown) remain. And this is exactly what our first spectrum showed: A periodic click train results in a harmonic spectrum.
</p>

<p>
Even though each click has a uniform spectrum, adding multiple clicks together cancels out all non-harmonic parts, and only a harmonic comb spectrum remains.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-signal-processing.html">signal-processing</a> ]]></description>
  <category><![CDATA[signal-processing]]></category>
  <link>https://bastibe.de/2019-09-19-periodicity-and-harmonicity.html</link>
  <guid>https://bastibe.de/2019-09-19-periodicity-and-harmonicity.html</guid>
  <pubDate>Thu, 19 Sep 2019 13:51:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[How we perceive Speech]]></title>
  <description><![CDATA[
<p>
Now that I am officially a <a href="https://bastibe.de/2019-07-09-publish-or-perish.html">failed scientist</a>, I might as well talk about my research in public. I spent the last few years analyzing speech recordings. Particularly, <i>voiced speech</i>, where vibrations in the vocal folds excite resonances in the vocal tract, and a tonal sound leaves our mouths and noses.
</p>

<p>
As humans, we are particularly tuned to recognizing these kinds of sounds. Even in loud background noise, even with dozens of people talking at the same time, we can clearly identify the sound of a human voice (even if we might not be able to understand the words).
</p>


<figure id="org4bc83a9">
<img src="https://bastibe.de/static/2019-09/spectrogram.png" alt="spectrogram.png">

<figcaption><span class="figure-number">Figure 1: </span>A spectrogram of speech (it's me, saying: "Es war einmal ein Mann")</figcaption>
</figure>

<p>
Looking at these sounds from a physical point of view, we can see that it is made up of a fundamental frequency at the voice's pitch, and harmonics at integer multiples of the fundamental. And even though the sound is clearly composed of multiple harmonics, we perceive it as a single sound with a single pitch. Even more perplexing, we attribute all of these harmonics to a single voice, even if they criss-cross with tonal sounds from different sources.
</p>

<p>
Yet, speech recognition systems regularly struggle with such tasks, unless we feed them unholy amounts of data and processing power. In other words, there has to be more to speech than the simple figure above indicates.
</p>

<p>
One area is definitely time resolution. Obviously, when the vocal folds open to admit a puff of air into the vocal tract, phases align, and loudness is higher than when the vocal folds have closed again and phases go out of sync. This happens several hundreds of times per second, at the frequency of the fundamental. Yet, this phase coherence is invisible in most of our visualizations, such as the spectrogram above, or the MFCCs usually used in speech recognition, as they are too coarse for such short-time detail.
</p>

<p>
An even more interesting detail emerges from fMRI scans of people who are speaking, and people who are listening to speech: their activation patterns are strikingly similar. As in, motor groups are activating when listening, just as if actual speech muscles were moved. To me, this indicates that when we listen to speech, we <i>simulate speaking</i>. And I find it highly likely that we understand speech mostly in terms of the movements we would have to make to imitate it. In other words, we do not internalize speech as an <i>audio</i> signal, but as <i>muscle movements</i>.
</p>

<p>
This matches another observation from a different area: When learning a foreign language, we can not hear what we can not produce. If you didn't learn how to speak an Ö and Ü (two German umlauts) as a child, you will have a hard time hearing the difference as an adult. Yet they sound completely distinct to me. In a production model, this makes a lot of sense, as we wouldn't know how to simulate a sound we can not produce.
</p>

<p>
Bringing this back to the science of signal processing, I believe that most speech analysis algorithms are currently lacking a production model of speech. Speech can not be fully understood as an audio signal. It needs to be understood in terms of the variables and limitations of a human vocal tract. I believe that if we integrated such a physiological production model into our machine learning models, we wouldn't need to feed them such vast amounts of data and electricity, and might even get by without them.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-signal-processing.html">signal-processing</a> <a href="https://bastibe.de/tag-science.html">science</a> ]]></description>
  <category><![CDATA[signal-processing]]></category>
  <category><![CDATA[science]]></category>
  <link>https://bastibe.de/2019-09-11-how-we-perceive-speech.html</link>
  <guid>https://bastibe.de/2019-09-11-how-we-perceive-speech.html</guid>
  <pubDate>Wed, 11 Sep 2019 16:35:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Publish or Perish]]></title>
  <description><![CDATA[
<p>
As part of my PhD, I am supposed to publish three papers. So far, I have been unable to do so. But this is not about me, I will survive regardless. This is about the <i>systems</i> behind our papers' rejections. Because they are&#x2026; <i>bad</i>. <i>Political</i>. <i>Un-scientific</i>.
</p>

<p>
Our first manuscript was submitted for publications, and got a middling review. If we wanted our work to be published, we were to expand on our introduction to mention the reviewers' favorite publications, and broaden our comparison to include their work. This is considered normal. In the second round of reviews we then got rejected, because our introduction was now too long, and our comparison too broad.
</p>

<p>
The reviews additionally claimed that "novelty cannot be claimed for something that is not validated and compared to state of the art" and that "[our work lacks] formal statistical evaluation of the estimation performance". Which is certainly true, but is also true of every other work published on the same topic in the last five years (I checked). We showed this evidence to the reviewers, but it was not even deemed worthy of a comment.
</p>

<p>
In hindsight however, we realized that we had included at least one reviewer's own algorithms in our comparison, and found it lacking. Their work had only ever been tested, publicly, with a single example recording, where it worked well. Our comparison did the same with twenty thousand recordings, which highlighted some issues. So our paper was rejected. Of course we can't be sure that this was ultimately true, as the reviewers' names are not disclosed to the reviewees (but certainly vice-versa).
</p>

<p>
Our next submission was to a different journal. This time, we had learned from our mistakes, and kept the scope of our investigation more minimal. There would be only a very small comparison, and we would be very careful not to step on anyone else's toes. The review was, again, negative.
</p>

<p>
This time, the grounds for rejection were lack of comparison to state of the art (not a winning move, see above), and our too high false negative rate. Additionally, it contained wonderful verbiage like:
</p>

<blockquote>
<p>
The are many methods that are very similar to the presented method in the sense of being feature extraction methods operating in the STFT domain.
</p>
</blockquote>

<p>
&#x2026;which is just patently ridiculous. If being a "feature extraction method in the STFT domain" was grounds for rejection, there would be <i>no</i> publications in our area of research. And let's ignore for a minute that our publication was not, in fact, such a method.
</p>

<p>
Again, hindsight showed the real culprit: Our manuscript reported a high false negative rate of roughly 50%. Had we just <i>not mentioned this</i>, no one would have noticed. That is what everyone else is doing. More importantly however, reporting on false positive/negative rates in our evaluation called into question every other publication that hadn't. And we can't have that.
</p>

<p>
Another submission was liked because no one had done anything similar before, and was found to provide value to many researchers, but rejected because it still somehow "lacked novelty".
</p>

<p>
So, in summary, our first submission was rejected because it made one of the reviewers look bad, and the second because we not only wanted to report on our method's advantages, but also its shortcomings. Worse, in following the evidence where it lead, we had created new error measures that could potentially find flaws in existing publications, which could potentially make a whole lot of researchers look bad.
</p>

<p>
After five years of dealing with this, I am thoroughly disheartened. Instead of a system for disseminating knowledge, I have found the scientific publishing system a political outlet for the famous, and a lever for keeping uncomfortable knowledge suppressed. This is not the scientific world I want to live in, and apparently, it doesn't want me to live in it, either.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-science.html">science</a> ]]></description>
  <category><![CDATA[science]]></category>
  <link>https://bastibe.de/2019-07-09-publish-or-perish.html</link>
  <guid>https://bastibe.de/2019-07-09-publish-or-perish.html</guid>
  <pubDate>Tue, 09 Jul 2019 13:48:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Fuji Zoom Lenses]]></title>
  <description><![CDATA[
<p>
So I bought a new camera. Now I need new lenses. In this post, I am looking for a standard zoom lens, i.e. something that covers a bit of wide-angle, all the way through the normal range, up to a bit of telephoto. In Fuji's lineup <a href="https://camerasize.com/compact/#721.706,721.421,721.359,721.426,721.448,721.388,ha,t">these needs are met by</a>
</p>

<ul class="org-ul">
<li><del>the XC 15‑45 mm f/3.5‑5.6 OIS PZ (€ 150, 136 g, 4.4 cm)</del></li>
<li>the XC 16‑50 mm f/3.5‑5.6 OIS II (€ 150, 195 g, 6.5 cm)</li>
<li>the XF 18‑55 mm f/2.8‑4 R LM OIS (€ 250, 310 g, 7.0 cm)</li>
<li>the XF 18‑135 mm f/3.5‑5.6 R LM OIS WR (€ 500, 490g, 9.8 cm)</li>
<li><del>the XF 16‑55 mm f/2.8 R LM WR (€ 650, 655 g, 10.6 cm)</del></li>
<li><del>a bag of primes (€ inf, many g, lots of cm)</del></li>
<li>the XF 27 mm f/2.8 (€ 150, 78 g, 2.3 cm)</li>
</ul>

<p>
The XC 15‑45 is out, because the zoom ring is not turn-to-zoom like any other zoom lens. I tried it; I couldn't stand it. The XF 16‑55 is out because it is just too expensive and big for me. A bag of primes is not what I want, but I included the XF 27, because that's what I happened to have at hand. All of the above prices are used prices as of early 2019 in Germany.
</p>


<figure id="orgf8ddb6a">
<img src="https://bastibe.de/static/2019-05/lenses.jpg" alt="lenses.jpg">

<figcaption><span class="figure-number">Figure 1: </span>From left to right, the XC 16‑50, XF 27, XF 18‑135, XF 18‑55</figcaption>
</figure>

<p>
Before we get started, all of these lenses are perfectly sharp to my eyes. At least in the center-ish area of the image, every pixel shows different information, which is not something I could have said about some of the Nikon lenses I used to own. Because of that, I will not compare sharpness.
</p>

<p>
The word of mouth is that the XF 18‑55 is a stellar kit lens, the XC 16‑50 is a bit cheap, and the XF 18‑135 a bit of a compromise. If internet forums are to be believed, these differences are massive, and the XF 18‑55 is really the only acceptable non-prime lens any self-respecting Fuji fanboy can buy. But then again, that's what internet forums <i>would</i> say, right?
</p>

<p>
With that out of the way, let's have a look at these lenses! I'll use crops from a terribly boring shot <a href="https://bastibe.de/static/2019-05/example.jpg">linked here</a> for most of my examples. Why this shot? Because a), that's what was available, and b), because it contains areas that nicely showcase these lenses' qualities. All shots were taken at f/8 at 27 mm, ISO 400 and a shutter speed around 1/300 s.
</p>

<div id="outline-container-org876989a" class="outline-2">
<h2 id="org876989a">Micro Contrast</h2>
<div class="outline-text-2" id="text-org876989a">
<p>
I often read that micro contrast really tells lenses apart. To illustrate this point, here's an area with very little overall contrast, particularly between the fence and the orange paint, and the fence and the gray stairs:
</p>


<figure id="org9a61c13">
<a href="https://bastibe.de/static/2019-05/microcontrast.jpg"><img src="https://bastibe.de/static/2019-05/microcontrast.jpg" alt="microcontrast.jpg"></a>

<figcaption><span class="figure-number">Figure 2: </span>100% crops, mouse pointers near the critical areas. (Click to view bigger)</figcaption>
</figure>

<p>
If you look very closely, you might find the fence slightly less visible on the XC 16‑50 than on the XF 18‑135 and XF 27, and ever so slightly more visible on the 18‑55. But it should also be obvious that these differences are <i>incredibly</i> tiny, and not worth fussing over.
</p>
</div>
</div>

<div id="outline-container-org0548e64" class="outline-2">
<h2 id="org0548e64">Corner Sharpness and Chromatic Aberrations</h2>
<div class="outline-text-2" id="text-org0548e64">
<p>
Another common point is corner sharpness, which is typically said to strongly favor primes. This time, the images are cropped from the bottom-right corner of the image that contains some detail, but most importantly a bright white warning sign:
</p>


<figure id="org8dd4585">
<a href="https://bastibe.de/static/2019-05/cornersharpness.jpg"><img src="https://bastibe.de/static/2019-05/cornersharpness.jpg" alt="cornersharpness.jpg"></a>

<figcaption><span class="figure-number">Figure 3: </span>100% crops of the image corner. (Click to view bigger)</figcaption>
</figure>

<p>
And indeed, the XC 16‑50 is noticeably blurry this time, with the other three lenses similarly sharp. The warning sign also highlights color fringes on the transitions from the bright white sign to the dark background. These chromatic aberrations are almost invisible on the XF 18‑55, and mild on the XF 18‑135 and XF 27.
</p>

<p>
Bear in mind, however, that these are 100% crops in the very furthest corners of a high-contrast image. In normal pictures, none of these issues will be noticeable unless you really zoom in on fine details at the edges of your frame. The chromatic aberrations seen here were already treated in software with the <i>lens correction</i> module in Darktable, but it might be possible to improve on these results with more dedicated processing.
</p>
</div>
</div>

<div id="outline-container-orgd27ba86" class="outline-2">
<h2 id="orgd27ba86">Update 1: Even more comparison pictures</h2>
<div class="outline-text-2" id="text-orgd27ba86">
<p>
After publishing the blog post, I still wasn't satisfied: What if the results I got were only true at f/8? What if image quality got worse at a longer focal length? How does my XF 18 stack up?
</p>

<p>
To answer this, I took another set of pictures and prepared another composite of an crops near the image center, and another one near the lower right corner.
</p>


<figure id="org0b52831">
<a href="https://bastibe.de/static/2019-05/centersharpness_big.jpg"><img src="https://bastibe.de/static/2019-05/centersharpness_big.jpg" alt="centersharpness_big.jpg"></a>

<figcaption><span class="figure-number">Figure 4: </span>100% crops of the image center. (Click to view bigger)</figcaption>
</figure>


<figure id="org481c0c9">
<a href="https://bastibe.de/static/2019-05/cornersharpness_big.jpg"><img src="https://bastibe.de/static/2019-05/cornersharpness_big.jpg" alt="cornersharpness_big.jpg"></a>

<figcaption><span class="figure-number">Figure 5: </span>100% crops of the image corner. (Click to view bigger)</figcaption>
</figure>

<p>
To be perfectly honest, I can not see any significant differences between any of these pictures. At this point, I am starting to question the entire concept of sharpness and micro contrast for evaluating lenses. But at least I learned a lot about how to use the Gimp.
</p>

<p>
As a sanity check, I repeated the experiment with my old Nikon 18-200, and this was in fact noticeably less sharp. And slightly overexposed. And slightly off-color. That's why I switched to Fuji. But as I said, this was a sanity check, not a fair comparison, as the Nikon D7000 body is much older than my Fuji X-E3, and the lens has surely seen better days as well.
</p>
</div>
</div>

<div id="outline-container-org444f0a9" class="outline-2">
<h2 id="org444f0a9">Update 1: Ergonomics and Balance</h2>
<div class="outline-text-2" id="text-org444f0a9">
<p>
The XC 16‑50 and XF 27 operate their aperture with the control wheel on your right thumb. The XC 18, XF 18‑55, and XF 18‑135 have a dedicated aperture ring on the lens instead. Thus, the former two lenses can be controlled with the right hand alone, while the latter two require the left hand on the lens barrel. Zoom is always controlled on the barrel, though.
</p>

<p>
This preference for one-handed or two-handed operation is supported by the lenses' weight, as well: My camera, the X-E3, weighs about 330 g. With the 200 g XC 16‑50, the weight is mostly in the camera body, and can easily be held and operated with one hand. The 250 g XF 18‑55 and the 500 g XF 18‑135 are more lens-heavy, which makes a two-handed grip necessary, which is a better fit for the aperture ring on the lens.
</p>

<p>
Personally, I actually prefer the aperture on the thumb wheel over the unmarked aperture rings on the XF 18‑55 and the XF 18‑135. It just feels more natural in my hands. On the other hand, I like the marked aperture ring on the XF 18, particularly for resetting the aperture without looking through the viewfinder, or when the camera is turned off. In fact, I find the ability to operate the camera while turned off to be very useful in general. It is one of the major reasons why I like Fuji cameras.
</p>
</div>
</div>

<div id="outline-container-org2280f8c" class="outline-2">
<h2 id="org2280f8c">Update 2: Image Stabilization</h2>
<div class="outline-text-2" id="text-org2280f8c">
<p>
In order to assess the image stabilization systems built into these lenses, I took a series pictures of a static subject at 18 mm, 27 mm, and 50 mm, for shutter speeds of 1/30 s, 1/15 s, 1/8 s, 1/4 s, and 1/2 s. I then looked at five images for every combination of lens, focal length, and shutter speed, and labeled them either <i>sharp</i> if there was no visible blur at all, or <i>usable</i> if there was micro-shake only visible at 100 %, or <i>miss</i> if the shot was too blurry.
</p>

<p>
The XC 16‑50 had perfect sharpness at 1/30 s, was at least ok between 1/15 s and 1/8 s, and even 1/4 s still had a few usable shots. 1/2 s or longer was unusable. There was no significant difference between the focal lengths. That last bit is really interesting, as I would have expected shorter focal lengths to be easier to hand-hold than longer ones.
</p>

<p>
The XF 18‑55 stayed perfectly sharp one stop longer until 1/15 s, but otherwise performed exactly the same as the XC 16‑50. I would guess that the small difference in stability between these two lenses is mostly due to their weight difference, but that the image stabilization system is identical.
</p>

<p>
The XF 18‑135, however, was another matter: All shots up until 1/8 s were perfectly sharp, and remained at least usable until 1/2 s! Only at 1 s of shutter speed did I see significant numbers of missed shots! Again, there was no significant difference across focal lengths.
</p>

<p>
With disabled image stabilization, I could hand-hold most shots for at most 1/focal length, but missed or fudged a few shots even there.
</p>

<p>
In summary, I found the XC 16‑50 and XF 18‑55 image stabilization good for about two stops, and astonishingly, the XF 18‑135 stable for a full four stops over my personal hand-holding skills. Some of that stability is no doubt due to the increased weight of the XF 18‑135, but nevertheless, I find these results astonishing!
</p>
</div>
</div>

<div id="outline-container-orge439fa0" class="outline-2">
<h2 id="orge439fa0">Close Focus Distance and Magnification</h2>
<div class="outline-text-2" id="text-orge439fa0">
<p>
And now, the darling of all photographers: out-of-focus backgrounds. Common wisdom is that the bigger the aperture, the more the background is thrown out of focus. But that's only part of the truth, and honestly, not the most interesting part for these kinds of limited-aperture lenses. Much more powerful is getting closer to your subject: The closer you focus, and the farther away your background, the more the background will be <i>out</i> of focus. This effect gets even stronger when you zoom in.
</p>


<figure id="org6a99848">
<a href="https://bastibe.de/static/2019-05/magnification.jpg"><img src="https://bastibe.de/static/2019-05/magnification.jpg" alt="magnification.jpg"></a>

<figcaption><span class="figure-number">Figure 6: </span>Widest (top) and longest (bottom) shots, each cropped vertically but not horizontally. All shots at f/5.6. (Click to view bigger)</figcaption>
</figure>

<p>
The XC 16‑50 focuses much more closely than any other lens in this list, at 12 and 30 cm (Fuji says 15 cm). You can get really nice background separation with this lens, and great magnification in your macro shots. The XF 18‑55 focuses at 25 and 35 cm (Fuji: 40 cm), which is not particularly impressive. The XF 18‑135 focuses even farther, at 33 and 43 cm (Fuji: 45 cm), but gains magnification through its long tele zoom. The XF 27 is not optimized for this kind of thing at all, at 29 cm (Fuji: 34 cm).
</p>
</div>
</div>

<div id="outline-container-org3c4a247" class="outline-2">
<h2 id="org3c4a247">Conclusions</h2>
<div class="outline-text-2" id="text-org3c4a247">
<p>
To me, the XC 16‑50 is the winner for a small/light zoom kit. It might be the least great option optically, but the differences are not dramatic at all, and it is the cheapest, smallest, and lightest lens with the most useful wide end and the closest focusing. But it lacks a dedicated aperture ring and is a plastic construction instead of a metal one, which does detract from the haptic joy somewhat.
</p>

<p>
The XF 18‑55 is optically the strongest lens. It might even beat the XF 27 prime lens on its own turf! But the optical differences to the cheaper XC 16‑50 and the more versatile XF 18‑135 are quite small, and are not be worth the price/weight/inconvenience to me.
</p>

<p>
The XF 18‑135 is really surprisingly good. The much longer focal range necessarily comes with compromises in optical quality and bulk, but it seems no significant corners where cut in this case. And the image stabilization is a significant step above the other two lenses. Considering that this lens usually replaces at least two other lenses, I even find the price reasonable. This is my first choice as a do-everything zoom kit.
</p>

<p>
The XF 27 is not very strong in any particular way, <i>except size</i>. And that size trumps all. If I just want to throw a camera in my bag without any particular photographic intentions, the XF 27 is my first choice. And possibly the XF 18, if I still have room in my bag.
</p>

<p>
As some small buying advice, the XC 16‑50 was refreshed in 2015 with the <i>OIS II</i> version, which introduced that nice close focusing distance (highly recommended). The XF 18‑135 was apparently built in two batches, the original <i>made in China</i> version that seemed to have horrible QA issues, and a second <i>made in Philippines</i> version in 2017 without.
</p>
</div>
</div>

<div id="outline-container-orgcb411c0" class="outline-2">
<h2 id="orgcb411c0">What I didn't mention</h2>
<div class="outline-text-2" id="text-orgcb411c0">
<p>
Aperture. The XF 18‑55 and XF 27 have a wider maximum aperture than the XC 16‑50 or XF 18‑135, by about two thirds of a stop. Shooting at bigger apertures makes brighter pictures with stronger background blur, and some loss in sharpness. I don't find the optical performance wide-open particularly interesting, because most of the time I'd use large apertures to blur the background, making sharpness and distortion mostly irrelevant. And as I said above, getting closer is usually more effective for background blur than maximum aperture, anyway.
</p>

<p>
Image stabilization. The three zooms offer optical image stabilization systems. From what I can tell, the XF 18‑135 is significantly more effective in this regard than the XC 16‑50 or the XF 18‑55. Hand-held shots with up to about 1/10th of a second seem easily achievable with the XF 18‑135, whereas the unstabilized XF 27 becomes blurry at 1/40th. Videos are noticeably smoother with the XF 18‑135 as well.
</p>

<p>
Weather sealing. The XF 18‑135 is weather sealed, the other lenses are not. My camera is not, so I don't care.
</p>

<p>
Distortion and Vignetting. Is fixed in post. No need obsessing over it.
</p>

<p>
Autofocus speed. Is good. No need obsessing over it.
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2019-05-11-fuji-zoom-lenses.html</link>
  <guid>https://bastibe.de/2019-05-11-fuji-zoom-lenses.html</guid>
  <pubDate>Sat, 11 May 2019 13:18:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[On camera sensor sizes]]></title>
  <description><![CDATA[
<p>
A common internet wisdom about photography is that bigger camera sensors capture more light. So if you want to work in low light, you need a full frame camera, and a bigger sensor always produces better image quality. I have struggled with this a lot. It just doesn't make sense: Lenses can focus light on any surface, so <i>why should the surface size matter</i>?
</p>

<p>
The answer turns out to be&#x2026; disappointing. Big-sensor cameras allow for larger (practical) apertures, and lower base ISO. But less noise for the same picture is simply impossible with the same sensor technology. Because that's not how physics works. Let me explain.
</p>

<p>
<i>At this point, I had previously launched into a long-winded explanation on <a href="https://photographylife.com/equivalence-also-includes-aperture-and-iso">equivalence</a>, and reached a slightly misguided conclusion. So here's a better one:</i>
</p>

<p>
It is possible to build <i>equivalent</i> lenses for differently sized sensors, which capture the same amount of light, with the same depth of field, and the same field of view, but simply project this light on a differently sized sensor. Or you can use a "speed booster", which adapts a "bigger" lens to a "smaller" sensor. Both of these will give you identical images, and identical amounts of noise (if the same sensor technology is used).
</p>

<p>
As an example, a micro four thirds 23mm f/1.4 lens produces identical images to an APS-C 35mm f/2 lens or a full frame 50mm f/2.8 lens. You might notice that \(\frac{23}{1.4} = \frac{35}{2} = \frac{50}{2.8}\), which means each of these lenses will have the same physical aperture size, and therefore admit the same amount of light. And be the same size and weight. Since the smaller sensor collects the same light on a smaller area, the image will be brighter, and will need to use a lower ISO for the same exposure. And since lower ISO produces less noise, the "one stop advantage" of bigger sensors is bunk, <i>if equivalent lenses are used</i>.
</p>

<p>
The one remaining difference between sensor sizes is that bigger photosites carry more charge, which means more dynamic range at base ISO on a bigger sensor. This is only a factor if you indeed shoot at base ISO.
</p>

<p>
<i>But</i>, that's not the interesting part. Camera manufacturers cleverly designed their product lines such that small-sensor cameras are physically smaller, and get smaller lenses, while large-sensor cameras are bigger, with bigger lenses. Thus, if you want to get access to the most fancy glass, you will have to use a bigger, more expensive camera body as well. And inversely, if you want to use the most compact glass, it will only be available on smaller, less expensive camera bodies. And that's not pure marketing, either, as bigger lenses require bigger bodies to hold them comfortably, while smaller lenses balance better on a smaller body.
</p>

<p>
So in the end, it comes down to a compromize: If you want/need the best glass, it will only be available on the bigger bodies with the bigger sensors. If, on the other hand, you want to go small and light, you will need to sacrifice big apertures, but get access to smaller bodies with smaller sensors. But it's really all about the glass, not the sensor sizes.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2019-03-25-on-camera-sensor-sizes.html</link>
  <guid>https://bastibe.de/2019-03-25-on-camera-sensor-sizes.html</guid>
  <pubDate>Mon, 25 Mar 2019 20:20:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Learning about Photography: Sunstars]]></title>
  <description><![CDATA[
<p>
Normally, when you take a picture of something too bright, you get <i>bloom</i>: An all-consuming brightness that plunges everything around it into pure whiteness. Ugly.
</p>

<p>
But if the light source is <i>reeeally</i> tiny, and your aperture is <i>teeeensy</i> as well, you get something else: sunstars
</p>


<figure id="org2106004">
<img src="https://bastibe.de/static/2019-03/sunstar.jpg" alt="sunstar.jpg">

</figure>

<p>
This particular sunstar has fourteen corners, and therefore comes from a seven-bladed aperture (in my Fuji XC 16-50). It happens because tiny apertures are not perfectly circular any longer, but instead, in my case, septagonal, and therefore bloom more in some directions than in others. The effect is kind of beautiful.
</p>

<p>
In this picture, the sun was just barely peeking into the edge between the tree and the building, and my aperture was set to its smallest setting, f22. I actually wanted to capture the raindrops on the branches, which I largely failed at. In the end, the picture didn't turn out very pretty, but at least I got some fine sunstars!
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2019-03-13-learning-about-photography-sunstars.html</link>
  <guid>https://bastibe.de/2019-03-13-learning-about-photography-sunstars.html</guid>
  <pubDate>Wed, 13 Mar 2019 20:17:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[What I learned about Amateur Photography]]></title>
  <description><![CDATA[
<p>
I am an amateur, as in "<a href="https://en.wikipedia.org/wiki/Amateur">lover of</a>", photography. I love cameras as tactile devices, I love how photography makes me consider the world as art, how that little viewfinder can reveal unknown beauty in well-known places or people. And I love looking at my photos, and remembering vacations and meaningful moments. For me, photography is about finding beauty, and capturing memories.
</p>

<p>
However, most of the writing on photography seems to be focused not on my needs, but the needs of professional photographers: A super competitive field of visual artists who compete on image quality and novelty, and use crazy and expensive gear. I have found many of their lessons not applicable to my amateur needs, or even actively detrimental:
</p>

<div id="outline-container-org1ee1ac0" class="outline-2">
<h2 id="org1ee1ac0">Embrace the noise</h2>
<div class="outline-text-2" id="text-org1ee1ac0">
<p>
Many pros limit their ISO numbers, because high-ISO noise is ugly. Which it is. But you know what is even worse for an amateur? Not having that picture of my baby, because it was too dark.
</p>

<p>
So I set my ISO to unlimited, reduce my shutter speed and aperture so I actually have a chance of capturing my fast-moving toddler. And embrace the ensuing noise. Some of my favorite pictures look unbearably noisy on my 4k screen, but look just fine when printed, or on a smartphone (the two most important mediums in the world).
Because of this, I find noise reduction rarely worth the effort. Color heavy noise reduction works ok, but anything else looks worse than the problem. I vastly prefer a sharp, noisy shot to a mushy denoised shot with no detail.
</p>
</div>
</div>

<div id="outline-container-orga04c22b" class="outline-2">
<h2 id="orga04c22b">Step it down</h2>
<div class="outline-text-2" id="text-orga04c22b">
<p>
Another common Pro argument: Wider apertures are better. Which they are, <i>at capturing light</i>, and <i>blurring the background</i>. But as an amateur, a wide-aperture super-shallow depth of field just makes me miss shots. At f1.8, the area in focus is barely a few centimetres deep. I missed too many shots because I accidentally focused on the nose instead of the eye. So, in the absence of studio lighting, and arbitrarily many retries, I prefer to step it down and live with the noise, if need be.
</p>

<p>
As a fun corollary, all those fancy prime lenses with crazy-wide apertures, they are simply wasted on me. Anything beyond, say, f2.8, is not something I need to spend money on.
Also, lenses are noticeably sharper when stepped down! I have been disappointed with the sharpness of a number of shots because I forgot to step it down. Nowadays, I typically shoot at f5.6 or f8, and only go wider if I actually need to, because of lack of light, or if I specifically want a blurry background.
</p>
</div>
</div>

<div id="outline-container-orgc96d4d1" class="outline-2">
<h2 id="orgc96d4d1">Wide-ish lenses are easier</h2>
<div class="outline-text-2" id="text-orgc96d4d1">
<p>
I wondered, for a long time, why pros seem to like long-ish lenses for portraits: The answer is, because longer lenses have a shallower the depth of field (for the same f-number), and pro photographers love their blurry backgrounds. But as I said before, that is not for me.
</p>

<p>
Instead, I prefer wide-ish lenses. If something is too small on a wide-ish lens, it is usually no problem to get a bit closer or to crop afterwards. If something is too big on a long lens though, backing off is often not possible, and you miss your shot<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>. Plus, wide-ish angles don't blur as much from shaky hands, and are more compact. They often focus more closely, too, which is a huge bonus if you want to take pictures of a toddler.
</p>

<p>
I have tried, unsuccessfully, a 50mm and 35mm prime (APS-C). Now I own a 27mm pancake prime, which I find perfect: long enough to get nice portraits, but still wide enough to capture a landscape.
</p>

<p>
Be careful with super-wide angle lenses, though. Even though they are a ton of fun, I have found anything below 16mm to be very difficult to <a href="https://www.kenrockwell.com/tech/how-to-use-ultra-wide-lenses.htm">use effectively</a>. It's just too easy to get that fisheye-distorted look, especially near the sides. That distorted look, by the way, is caused by being too close, not by lens distortion. The same thing happens if you take a longer lens or a cell phone and get too close. Just don't do that.
</p>
</div>
</div>

<div id="outline-container-orge9cc274" class="outline-2">
<h2 id="orge9cc274">Gear</h2>
<div class="outline-text-2" id="text-orge9cc274">
<p>
Pros use the biggest sensor they can get, to get the best image quality possible. But that also makes everything else much more cumbersome: Bigger sensors mean bigger and heavier bodies. And bigger and heavier lenses. And shallower depth of field (see above). And smaller focal ranges, hence more lens changing. And, not least of all, much, much, much higher prices. It is not for me.
</p>

<p>
To some extent, the same goes for different quality levels: Personally, I have found entry-level APS-C mirrorless interchangeable lens cameras a good compromise. These entry-level plastic lenses and cameras are usually smaller, lighter, and cheaper than their higher-end brethren, but compromise on robustness and aperture sizes (e.g. <a href="https://camerasize.com/compact/#493.421,520.359,7.351,ha,t">Fuji X-E2 375g/€250 + Fuji XC 16-50mm, 195g/€150 vs. Fuji X-T1 450g/€250 + Fuji XF 18-55mm, 300g/€250 vs. my old Nikon gear</a>). And for my everyday camera, I' take a <a href="https://camerasize.com/compact/#493.388,ha,t">smaller, pocketable camera</a> over a "better", bigger one any day.
</p>

<p>
Haptics are important, too. I have seen great cameras and lenses that just didn't feel good in my hand. Which meant I wouldn't ever take them with me, and wouldn't take any pictures with them. I now go try stuff in the store before I buy anything. This has talked me out of a number of unnecessary purchases, internet consensus notwithstanding.
</p>

<p>
And finally, I buy used gear. Cameras and lenses depreciate about 70% within the first two years, without losing any quality. A great camera from two years ago is still a great camera, but costs a third of the original price, and can be resold without loss. And is better for the environment. Win-win-win.
</p>
</div>
</div>

<div id="outline-container-org807944a" class="outline-2">
<h2 id="org807944a">TL;DR</h2>
<div class="outline-text-2" id="text-org807944a">
<p>
I have found many "common" rules about photography useless for my amateur needs. I have found cheap, plastic, used gear more useful than pro gear. I have found noisy, small-aperture pictures to be better at capturing important memories than clean, "professional" ones. I have found haptics, size and weight to be much more important than ultimate image quality (within reason).
</p>

<p>
The funny thing is, you don't find this kind of information on the internet, since most review websites seem to focus on the professional viewpoint, even for gear that is clearly meant for amateurs like me.
</p>
</div>
</div>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
You need to back off much farther on a long lens than you have
to move closer on a wide lens.
</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-photography.html">photography</a> ]]></description>
  <category><![CDATA[photography]]></category>
  <link>https://bastibe.de/2019-02-24-what-i-learned-about-amateur-photography.html</link>
  <guid>https://bastibe.de/2019-02-24-what-i-learned-about-amateur-photography.html</guid>
  <pubDate>Sun, 24 Feb 2019 10:50:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Books of 2018]]></title>
  <description><![CDATA[
<p>
There is no other media more immersive to me than reading. When I read, I dive deep into another world, and seize to perceive the reality around me. It is my escape from the everyday stresses of living in the modern world. Reading is truly sacred to me. So here are my favorite pieces of writing of 2018:
</p>

<div id="outline-container-orgc4870d2" class="outline-2">
<h2 id="orgc4870d2"><a href="https://www.goodreads.com/book/show/9530.Shadow_Divers">Shadow Divers</a></h2>
<div class="outline-text-2" id="text-orgc4870d2">

<figure id="orga6daa60">
<img src="https://bastibe.de/static/2019-01/shadow-divers-cover.jpg" alt="shadow-divers-cover.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<p>
This is a book about deep wreck diving. I am not interested in wrecks, or diving. Nevertheless, no book gripped me as hard last year as Shadow Divers. At first, I was a bit thrown off by the writing style, and thought it dramatized things too much. But I just couldn't put this book down. There were times when I surfaced from reading with a distinct feeling of having been there, of having touched that menacing shipwreck at the bottom of the ocean.
</p>

<p>
By the end of it, I was entirely engrossed in the story and its characters and the history of the mystery wreck. And then, in the epilogue, I learned that what I had thought embellished at first was actually meticulously researched and not overdramatic at all.
</p>

<p>
And best of all, my favorite podcast, <a href="http://omegataupodcast.net">Omega Tau</a> had <a href="http://omegataupodcast.net/33-deep-wreck-diving/">an interview</a> with the main protagonist of the book, which is just fascinating!
</p>
</div>
</div>

<div id="outline-container-org6ba0fa6" class="outline-2">
<h2 id="org6ba0fa6"><a href="https://www.goodreads.com/book/show/34757960-the-shortest-history-of-germany">The Shortest History of Germany</a></h2>
<div class="outline-text-2" id="text-org6ba0fa6">

<figure id="org29533b5">
<img src="https://bastibe.de/static/2019-01/german-history-cover.jpg" alt="german-history-cover.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<p>
This book is a strange choice to put on my list of books, because I didn't like it too much. I found it offputting which parts of history the author emphasized, and which parts he skipped. Apparently, the two world wars did not bear mentioning. The book paints a strangely specific west-vs-east map of Germany, which is not without merit, but surely not the whole story. And worst of all, I really didn't care for the writing style at all.
</p>

<p>
But when I look back on 2018, this book has stuck with me. Never mind its shortcomings, it has given me a map of Germany's history that I can fit other pieces of knowledge into. And that makes it valuable to me.
</p>
</div>
</div>

<div id="outline-container-orgaa4cdf7" class="outline-2">
<h2 id="orgaa4cdf7"><a href="https://uncannymagazine.com/article/and-then-there-were-n-one/">And then there were (N-One)</a></h2>
<div class="outline-text-2" id="text-orgaa4cdf7">

<figure id="orgc098fa1">
<img src="https://bastibe.de/static/2019-01/n-1-cover.jpg" alt="n-1-cover.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<p>
I love short stories. And this one is just brilliant. It is by Sarah Pinsker, about Sarah Pinsker, and all Sarah Pinskers from neighboring parallel universes. Every character in this book is a Sarah Pinsker. And all of them agree, Sarah is no murderer. Yet, one of them has been found murdered.
</p>

<p>
I won't spoil more of it, just head over to the <a href="https://uncannymagazine.com/article/and-then-there-were-n-one/">Uncanny Magazine</a> and read it for yourself!
</p>

<br><br>
</div>
</div>

<div id="outline-container-orgcc7f836" class="outline-2">
<h2 id="orgcc7f836">Graphic Novels</h2>
<div class="outline-text-2" id="text-orgcc7f836">
<p>
For years now, I have struggled to find graphic novels that speak to me. I usually find the drawing style off-putting, and would have preferred a more fleshed out novel instead of a shallow graphic novel. But this year, I found two brilliant graphic novels that I loved dearly:
</p>
</div>

<div id="outline-container-org7a24229" class="outline-3">
<h3 id="org7a24229"><a href="https://www.goodreads.com/book/show/15195.The_Complete_Maus">Maus</a></h3>
<div class="outline-text-3" id="text-org7a24229">

<figure id="org473d84b">
<img src="https://bastibe.de/static/2019-01/maus-cover.jpg" alt="maus-cover.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<p>
The half-auto-biographical narrative of a survivor of one the Nazi concentration camps. The novel juxtaposes the author's struggle to interview his father about his past, and thereby shows both the cruelty of the father's experience, and the man that this experience created. Both of these perspectives add weight to the unspeakable nastiness of the Holocaust.
</p>

<p>
But beyond that, it is also a story of humanity, struggle, and the small moments of joy amidst all the terror. Truly a masterpiece of a book.
</p>
</div>
</div>

<div id="outline-container-org3163093" class="outline-3">
<h3 id="org3163093"><a href="https://www.goodreads.com/book/show/19351043-nimona">Nimona</a></h3>
<div class="outline-text-3" id="text-org3163093">

<figure id="org712c45b">
<img src="https://bastibe.de/static/2019-01/nimona-cover.jpg" alt="nimona-cover.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<p>
In sharp contrast to the previous book, Nimona is just plain fun! Nimona is a teenage girl, and a shark, and the sidekick of Balister Blackheart, the biggest name in Supervillainy. And if you haven't guessed it from this description, it is wacky, and funny, and uplifting, and just&#x2026; fun!
</p>

<p>
You can read the first three chapters <a href="http://gingerhaze.com/nimona">online</a>, and then you'll want to read the rest, too. It's just too much fun!
</p>
</div>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-books.html">books</a> ]]></description>
  <category><![CDATA[books]]></category>
  <link>https://bastibe.de/2019-01-06-books-of-2018.html</link>
  <guid>https://bastibe.de/2019-01-06-books-of-2018.html</guid>
  <pubDate>Sun, 06 Jan 2019 10:54:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Cool Python Libraries: TQDM and Resampy]]></title>
  <description><![CDATA[
<p>
In my recent post about <a href="https://bastibe.de/2018-10-14-appreciation-for-open-source-and-commercial-software.html">appreciation for open source software</a>, I mentioned that we should praise our open source heros more often. So here are two lesser-known libraries that I use daily, and which are unabashedly awesome:
</p>

<div id="outline-container-org7562828" class="outline-2">
<h2 id="org7562828"><a href="https://tqdm.github.io/">TQDM</a></h2>
<div class="outline-text-2" id="text-org7562828">
<p>
TQDM draws text progress bars for long-running processes, simply by wrapping your iterator in <code>tqdm(iterator)</code>. And this, alone, would be awesome. But, TQDM is one of those libraries that aren't just a good idea, but then go the extra mile, and add fantastic documentation, contingencies for all kinds of weird use cases, and integration with notebooks and GUIs.
</p>

<p>
I use TQDM all the time, for running my scientific experiments and data analysis, and it just works. For long-running tasks, I recommend using <code>tqdm(iterator, smoothing=0, desc='calculating')</code>, which adds a meaningful description to the progress bar, and an accurate runtime estimate.
</p>
</div>
</div>

<div id="outline-container-orga7011af" class="outline-2">
<h2 id="orga7011af"><a href="https://resampy.readthedocs.io/en/latest/">Resampy</a></h2>
<div class="outline-text-2" id="text-orga7011af">
<p>
Resampy resamples numpy signals. Resample your data with <code>resample(signal, old_samplerate, new_samplerate)</code>. Just like with TQDM, this simple interface hides a lot of complexity and flexibility under the hood, yet remains conceptually simple and easy to use.
</p>

<p>
But beyond simplicity, resampy uses a clever implementation that is a far cry better than <code>scipy.signal.resample</code>, while still being easy to install and fast. For a more thorough comparison of resampling algorithms, visit <a href="https://signalsprocessed.blogspot.com/2016/08/audio-resampling-in-python.html">Joachim Thiemann's blog</a>.
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-python.html">python</a> ]]></description>
  <category><![CDATA[python]]></category>
  <link>https://bastibe.de/2018-11-08-cool-python-libraries.html</link>
  <guid>https://bastibe.de/2018-11-08-cool-python-libraries.html</guid>
  <pubDate>Thu, 08 Nov 2018 14:52:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Dealing with Unreliable Software]]></title>
  <description><![CDATA[
<p>
About a year ago, I started working on a big comparison study between a bunch of scientific algorithms. Many of these have open-source software available, and I wanted to evaluate them with a large variety of input signals. The problem is, this is <a href="https://bastibe.de/2017-05-14-scientific-code.html">scientific code</a>, i.e. the worst code imaginable.
</p>

<p>
Things this code has done to my computer:
</p>
<ul class="org-ul">
<li>it crashed, throwing an error, and shutting down nicely</li>
<li>it crashed with a segfault, taking the owning process with it</li>
<li>it crashed, leaving temporary files lying around</li>
<li>it crashed, leaving zombie processes lying around</li>
<li>it spin-locked, and never returned</li>
<li>it spin-locked, and forked uncontrollably until all process decriptors were exhausted</li>
<li>it spin-locked, and ate memory uncontrollably until all memory was consumed</li>
<li>it crashed other, unrelated programs (no idea how it managed that)</li>
<li>it corrupted the root file system (no idea how it managed that)</li>
</ul>

<p>
Note that the code did not do any of this intentionally. It was merely code written by non-expert programmers, the problems often a side effect of performance optimizations. The code mostly works fine if called only once or twice. My problems only become apparent if I ran it, say, a few hundred thousand times, with dozens of processes in parallel.
</p>

<p>
So, how do you deal with this? Multi-threading is not an option, since a segfault would kill the whole program. So it has to be multi-processing. But all the multi-processing frameworks I know will lose all progress if one of the more sinister scenarios from the above list hard-crashed one or more of its processes. I needed a more robust solution.
</p>

<p>
Basically, the only hope of survival at this point is the kernel. Only the kernel has enough power to rein in rogue processes, and deal with hard crashes. So in my <a href="https://github.com/bastibe/runforrest">purpose-built multi-processing framework</a>, every task runs in its own process, with inputs and outputs written to unique files. And crucially, if any task does not finish within a set amount of time, it and all of its children are killed.
</p>

<p>
It took me quite a while to figure out how to do this, so here's the deal:
</p>

<div class="org-src-container">
<pre class="src src-python"># start your process with a new process group:
process = Popen(..., start_new_session=True)

# after a timeout, kill the whole process group:
process_group_id = os.getpgid(process.pid)
os.killpg(process_group_id, signal.SIGKILL)
</pre>
</div>

<p>
This is the nuclear option. I tried <code>SIGTERM</code> and <code>SIGHUP</code> instead, but programs would happily ignore it. I tried killing or terminating only the <code>process</code>, but that would leave zombie children. Sending <code>SIGKILL</code> to the process group does not take prisoners. The processes do not get a chance to respond or clean up after themselves. But you know what, after months of dealing with this stuff, this is the first time that my experiments actually run reliably for a few days without crashing or exhausting some resource. If that's what it takes, so be it.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <link>https://bastibe.de/2018-10-26-dealing-with-unreliable-software.html</link>
  <guid>https://bastibe.de/2018-10-26-dealing-with-unreliable-software.html</guid>
  <pubDate>Fri, 26 Oct 2018 09:45:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Appreciation for Open Source and Commercial Software]]></title>
  <description><![CDATA[
<p>
I recently released my first-ever piece of commercial software, a <a href="https://missiongenerator.eu/">plugin</a> for the <a href="https://www.x-plane.com/">X-Plane</a> flight simulator. I wrote this primarily to scratch my own itch, but thought other users might like it, too, so I put it up on <a href="https://store.x-plane.org/Mission-Generator_p_877.html">the store</a>. What struck me however, were the stark difference between the kinds of responses I got to this, as compared to my open source projects: They were astonishingly, resoundingly, <i>positive</i>!
</p>

<p>
You see, I have a bunch of open source projects, with a few thousand downloads per month, and a dozen or so issues on Github per week. Most of my interactions with my users are utilitarian, and efficient. Someone reports a bug or asks for help, I ask for clarification or a pull request, we iterate a few times until the issue is resolved. The process is mechanical and the tone of our conversation is equally unemotional. This is as it should be.
</p>

<p>
After having released my flight simulator plugin, however, people <i>thanked me</i>! They <i>congratulated me</i>! They extolled about the greatness of what I had built! And they did this despite the fact that the initial release had quite a few major bugs, and even flat-out did not work for some people. Yet even people who couldn't get it to work were <i>grateful</i> for my help in resolving their issue!
</p>

<p>
This <i>blew my mind</i>, in comparison with the drab "I found a bug", "Could you implement…" I was used to from my open source work. There, the feedback I got was mostly neutral (bug reports, feature requests), and sometimes even negative ("You broke something!"). So I release my software <i>for free</i>, as a gift, and get average-negative feedback. My commercial work, in contrast, <i>costs money</i>, and yet the feedback I get is resoundingly positive! I can not overstate how motivating it is to get praise, and love, from my users.
</p>

<p>
I think this is a huge problem for our Open Source community. I had my run-ins with burnout, when all the pull requests came to be too much, and I started dreading the little notification icon on Github. And I think the negativity inherent in bug reports and feature requests has a huge part to do with this. In the future, I will try to add more praise to my bug reports from now on, just to put things into perspective.
</p>

<p>
But I think we should go further than that. We should create tools for praising stuff, beyond the impersonal Stars on Github. We should be able to write reviews on Github, and recommendations, and blog posts about cool libraries we find.
</p>

<p>
I recently got my first github issue that was <a href="https://github.com/bastibe/org-static-blog/issues/12">just a thank-you note</a>. I loved it! We need more positivity like that.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-open-source.html">open-source</a> <a href="https://bastibe.de/tag-thank-you.html">thank-you</a> ]]></description>
  <category><![CDATA[open-source]]></category>
  <category><![CDATA[thank-you]]></category>
  <link>https://bastibe.de/2018-10-14-appreciation-for-open-source-and-commercial-software.html</link>
  <guid>https://bastibe.de/2018-10-14-appreciation-for-open-source-and-commercial-software.html</guid>
  <pubDate>Sun, 14 Oct 2018 10:20:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Syncing Org-Journal with your Calendar]]></title>
  <description><![CDATA[
<p>
<a href="https://bastibe.de/2018-04-02-scheduling-future-todos-in-org-journal.html">A month ago</a>, org-journal learned to deal with future journal entries. I use future journal entries for appointments or not-yet-actionable tasks that I don't want in my current TODO list just yet. This works really well while I am at my computer, and really does not work at all when I am not (<a href="http://www.orgzly.com/">Orgzly</a> does <i>not</i> work with my 1k-file journal directory).
</p>

<p>
But, as I keep re-discovering, org-mode already has a solution for this: org-mode can export your agenda to an iCalendar file! Most calendar applications can then subscribe to that file, and show your future journal entries right in your calendar. And if you set it up right, this will even sync changes to your calendar!
</p>

<p>
First, you need to set up some kind of regular export job. I use a cron job that regularly runs an Emacs batch job <code>emacs --batch --script ~/bin/calendar_init.el</code> with the following code in <i>calendar​_init.el</i>:
</p>

<div class="org-src-container">
<pre class="src src-elisp">;; no init file is loaded, so provide everything here:
(add-to-list 'load-path "~/etc/org-journal/")
(setq org-journal-dir "~/journal/"            ; where my journal files are
      org-journal-file-format "%Y-%m-%d.org"  ; their file names
      org-journal-enable-agenda-integration t ; so entries are on the agenda
      org-icalendar-store-UID t               ; so changes sync correctly
      org-icalendar-include-todo "all"        ; include TODOs and DONEs
      org-icalendar-combined-agenda-file "~/calendar/org-journal.ics")

(require 'org-journal)
(org-journal-update-org-agenda-files) ; put future entries on the agenda
(org-icalendar-combine-agenda-files)  ; export the ICS file
(save-buffers-kill-emacs t)           ; save all modified files and exit
</pre>
</div>

<p>
It is important to set <code>org-icalendar-store-UID</code>, as otherwise every change to a future entry would result in a duplicated calendar entry. It will clutter up your journal entries with an <code>UID</code> property, though.
</p>

<p>
I do this on my web server, with my journal files <a href="https://syncthing.net/">syncthing</a>ed from my other computers. With that, I can subscribe to the calendar file from any internet-connected computer or mobile phone (using <a href="https://icsdroid.bitfire.at/">ICSdroid</a>). But you could just as well sync only the ICS file, or just subscribe to the local file, if you don't want to upload your complete yournal to a web server.
</p>

<p>
(Incidentally, I first implemented my own ICS export, before realizing that this functionality already existed in org-mode. It was a fun little project, and I learned a lot about org-mode's internal data structures and the weirdness that are iCalendar files.)
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-org-journal.html">org-journal</a> ]]></description>
  <category><![CDATA[org-journal]]></category>
  <link>https://bastibe.de/2018-06-03-syncing-org-journal-with-your-calendar.html</link>
  <guid>https://bastibe.de/2018-06-03-syncing-org-journal-with-your-calendar.html</guid>
  <pubDate>Sun, 03 Jun 2018 10:28:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[GDPR Compliance]]></title>
  <description><![CDATA[
<p>
Personal email is dead. The signal-to-noise ratio of my personal email account has been deeply negative for years. But the last few days have been especially riveting, with a torrent of GDPR-compliance emails from just about every company that has ever gotten their hands on my email address. Anecdotally, if spam makes up about 90% of all email traffic, and the last few days have seen a ten-fold increase in traffic due to GDPR emails, we might even have "defeated spam" for a few days! Yay internet!
</p>

<p>
But sadly, I can't add to the signal-to-noise ratio, because this website does not collect any email addresses. And even more sadly, it doesn't even collect IP addresses, or use any kind of analytics at all. Sorry about that. I honestly do not know how many people read my stuff, and I can not rank my blog posts by their popularity. And I like it that way. It prevents me from getting on any kind of treadmill to please any kind of imagined audience.
</p>

<p>
That is&#x2026; with one exception: Comments on this website are powered by Disqus, and I'm sure Disqus collects all kinds of data about all kinds of things. That's why comments are now hidden behind a "Load Disqus Comments" button. I promise you that no foreign Javascript is executed unless you press that button<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>. And honestly, GDPR didn't even have anything to do with that. I just didn't want any foreign JavaScript.
</p>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
Unless <a href="https://github.com/Khan/KaTeX">katex.min.js</a> somehow is loading external javascript&#x2026;
</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-privacy.html">privacy</a> <a href="https://bastibe.de/tag-blog.html">blog</a> ]]></description>
  <category><![CDATA[privacy]]></category>
  <category><![CDATA[blog]]></category>
  <link>https://bastibe.de/2018-05-25-gdpr-compliance.html</link>
  <guid>https://bastibe.de/2018-05-25-gdpr-compliance.html</guid>
  <pubDate>Fri, 25 May 2018 17:21:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Appending to Matlab Arrays]]></title>
  <description><![CDATA[
<p>
<i>The variable $var appears to change size on every loop iteration. Consider preallocating for speed.</i>
</p>

<p>
So sayeth Matlab.
</p>

<p>
Let's try it:
</p>

<div class="org-src-container">
<pre class="src src-octave">x_prealloc = cell(10000, 1);
x_end = {};
x_append = {};
for n=1:10000
    % variant 1: preallocate
    x_prealloc(n) = {42};
    % variant 2: end+1
    x_end(end+1) = {42};
    % variant 3: append
    x_append = [x_append {42}];
end
</pre>
</div>

<p>
Which variant do you think is fastest?
</p>


<figure id="org14b38cf">
<img src="./static/2018-04/array_performance.png" alt="array_performance.png">

</figure>

<p>
Unsurprisingly, preallocation is indeed faster than growing an array. What <i>is</i> surprising is that it is faster by a constant factor of about 2 instead of scaling with the array length. Only appending by <code>x = [x {42}]</code> actually becomes slower for larger arrays. (The same thing happens for numerical arrays, struct arrays, and object arrays.)
</p>

<p>
<b>TL;DR:</b> Do not use <code>x = [x $something]</code>, ever. Instead, use <code>x(end+1) = $something</code>. Preallocation is generally overrated.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-matlab.html">matlab</a> ]]></description>
  <category><![CDATA[matlab]]></category>
  <link>https://bastibe.de/2018-04-10-appending-to-matlab-arrays.html</link>
  <guid>https://bastibe.de/2018-04-10-appending-to-matlab-arrays.html</guid>
  <pubDate>Tue, 10 Apr 2018 13:48:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Defeating News Addiction]]></title>
  <description><![CDATA[
<p>
I want to consume the news, both because it is genuinely relevant for my work, and because conversations about news are part of my social life. But I do not want to be consumed by news, and end up scanning news websites over and over for new content, even though you know that the likelihood of finding anything interesting is small.
</p>

<p>
Over the last few months, I have tried hard to find all instances of this repeated-scanning behavior, and eliminate it. The key is to automate the scanning such that I am only ever presented with new content, but do not get hooked on the addictive variable-reward cycle of checking websites for changes over and over again.
</p>

<p>
And it all works thank to the magic of RSS:
</p>

<ul class="org-ul">
<li><b>News Sources:</b>
I read several blogs, newspapers, and webcomics. All of them have RSS feeds. Easy.</li>

<li><b>Hacker News:</b>
The brilliant service <a href="https://hnrss.org/">hnrss.org</a> provides RSS feeds for Hacker News, and filters them to for example only include posts that made it to the front page, and have accumulated <a href="https://hnrss.org/frontpage?points=100">at least 100 points</a>.</li>

<li><b>Reddit:</b>
Every subreddit has its own feed, at <a href="https://www.reddit.com/r/emacs.rss">reddit.com/r/subreddit.rss</a>. Sadly there is no way to filter for a minimum number of upvotes.</li>

<li><b>YouTube:</b>
Again, every YouTube channel has its own RSS feed, but Google is trying very hard to make it as cumbersome as possible to get at those feeds. You need to go to your <a href="https://www.youtube.com/subscription_manager">Subscription Manager</a>, then scroll all the way down, and "Export Subscriptions". The resulting file helpfully does not have a file extension, which you will have to add before you can import it into your RSS reader. I honestly can't reconstruct how I found that subscription manager, either, but presumably there is some series of clicks that would take you there.</li>
</ul>

<p>
With all this settled, I have a veritable firehose of news every day. I estimate that only 1 % of this is actually worth reading. So in the next step, I filter this list for spam. For this purpose, I use <a href="https://feedbin.com/">Feedbin</a>, which aggegates all these feeds, and remembers whether I have read an article. The remaining ham I either read immediately, or forward it to <a href="http://pinboard.in/">Pinboard</a> for later consumption.
</p>

<p>
With this system, I never miss anything, but once I consume all the news in my feed reader, I know I am done, and there is no point in checking and re-checking various websites over and over again.
</p>

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="422" height="70">
  <!-- grey achievement box: -->
  <rect x="0" y="1" rx="32" ry="32" width="422" height="64" fill="#3A3E3F" />
  <!-- black background circle: -->
  <circle cx="33" cy="33" r="28" fill="#15150D" />
  <!-- top left sector (green): -->
  <path d="M 9 30
           A 24 24 0 0 1 30 9
           L 30 15
           A 18 18 0 0 0 15 30"
        fill="#69B168" />
  <!-- top right sector (grey): -->
  <path d="M 36 9
           A 24 24 0 0 1 57 30
           L 51 30
           A 18 18 0 0 0 36 15"
        fill="#595B5A" />
  <!-- bottom right sector (grey): -->
  <path d="M 57 36
           A 24 24 0 0 1 36 57
           L 36 51
           A 18 18 0 0 0 51 36"
        fill="#595B5A" />
  <!-- bottom left sector (grey): -->
  <path d="M 30 57
           A 24 24 0 0 1 9 36
           L 15 36
           A 18 18 0 0 0 30 51"
        fill="#595B5A" />
  <!-- XBox image (source unknown): -->
  <image xlink:href="static/2018-04/xbox.png" x="18" y="18" width="30px" height="30px" />
  <!-- text labels: -->
  <text x="76" y="27" font-family="Verdana" font-size="13px" fill="#E1E6E7">ACHIEVEMENT UNLOCKED</text>
  <text x="76" y="48" font-family="Verdana" font-size="13px" fill="#E1E6E7">Defeated News Addiction!</text>
</svg>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-workflow.html">workflow</a> ]]></description>
  <category><![CDATA[workflow]]></category>
  <link>https://bastibe.de/2018-04-07-defeating-news-addiction.html</link>
  <guid>https://bastibe.de/2018-04-07-defeating-news-addiction.html</guid>
  <pubDate>Sat, 07 Apr 2018 10:02:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Scheduling Future TODOs in org-journal]]></title>
  <description><![CDATA[
<p>
I keep a simple journal in <a href="https://github.com/bastibe/org-journal">org-journal</a>: One text file per day, in <a href="https://orgmode.org/">org-mode</a>. But over the years, org-journal has grown somewhat beyond this simple use case. <a href="https://github.com/bastibe/org-journal/releases/tag/1.7.1">About three years ago</a>, a gentleman named <a href="https://github.com/vkazanov">Vladimir Kazanov</a> implemented a very fast text search. Thus, my journal became an information archive. <a href="https://github.com/bastibe/org-journal/releases/tag/1.11.0">About two years ago</a>, org-journal learned to carry over TODO items to the current day if you hadn't completed them on the previous day. So it to become a to-do list. And <a href="https://github.com/bastibe/org-journal/releases/tag/1.13.1">today</a>, org-journal gained the ability to work with future journal entries, thus becoming a calendar.
</p>

<p>
Despite all of these features however, org-journal remains one org file per day, with fancy functions to do fancy things if you want them—or ignore them, if the journal is all you need.
</p>

<p>
Back to scheduling: This work was prompted by <a href="https://zngguvnf.org/">my colleague</a>, who organizes everything in org-mode, but is not a user of org-journal. He even eschews the use of a traditional calendar, and instead uses a few org files and the magic of org-agenda to give him a nice overview like this for the coming week[1]:
</p>

<pre>
<span style="color: #111111; font-weight: bold;">Week-agenda (W14):</span>
<span style="color: #111111; font-weight: bold; font-style: italic;">Monday     2 April 2018 W14</span>
<span style="color: #111111;">  2018-04-02: Easter Monday </span>
<span style="color: #111111; font-weight: bold;">Tuesday    3 April 2018</span>
<span style="color: #111111; font-weight: bold;">Wednesday  4 April 2018</span>
<span style="color: #111111; font-weight: bold;">Thursday   5 April 2018</span>
<span style="color: #111111;">  2018-04-05: Scheduled:  Give Lecture 4 on Applied Programming</span>             <span style="color: #111111;"><span style="font-weight: bold;">:BB:</span></span>
<span style="color: #111111; font-weight: bold;">Friday     6 April 2018</span>
<span style="color: #111111;">  2018-04-06: Scheduled:  Release of new Eels record</span>
<span style="color: #111111; font-weight: bold;">Saturday   7 April 2018</span>
<span style="color: #111111; font-weight: bold;">Sunday     8 April 2018</span>
<span style="color: #111111;">  2018-04-08: Scheduled:  </span><span style="color: #111111;">TODO</span><span style="color: #111111;"> Celebrate Sunday</span>
</pre>

<p>
And lo and behold, this now works in org-journal as well! Just create a new journal entry in the future, either by pressing <code>i j</code> in <code>M-x calendar</code> or by calling <code>org-journal-new-scheduled-entry</code>, and org-journal will create an entry with a <code>SCHEDULED</code> property of the appropriate date (prefix to suppress <code>TODO</code>). When the current day reaches that entry, it will incorporate it into the daily journal.
</p>

<p>
Future journal entries are highlighted in <code>M-x calendar</code>, and you can get an overview of them with <code>org-journal-schedule-view</code>, or, if you enable <code>org-journal-enable-agenda-integration</code>, through the ordinary <code>org-agenda</code>, as shown above. The agenda integration does not include past journal entries in the agenda, since agenda searches tend to become very slow if they have to traverse the hundreds of files in my journal.
</p>

<p>
[1]: This is of course not <i>his</i> calendar, but mine.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-org-journal.html">org-journal</a> <a href="https://bastibe.de/tag-org-mode.html">org-mode</a> ]]></description>
  <category><![CDATA[org-journal]]></category>
  <category><![CDATA[org-mode]]></category>
  <link>https://bastibe.de/2018-04-02-scheduling-future-todos-in-org-journal.html</link>
  <guid>https://bastibe.de/2018-04-02-scheduling-future-todos-in-org-journal.html</guid>
  <pubDate>Mon, 02 Apr 2018 11:38:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Blogging with org-static-blog (Updated)]]></title>
  <description><![CDATA[
<p>
A while ago, I scratched an old itch and wrote my own static site generator, called <a href="https://github.com/bastibe/org-static-blog">org-static-blog</a>. It is a simple thing: You hand it a directory full of *.org files with a <code>#+title:</code> and <code>#+date:</code>, and it assembles a bunch of HTML pages and an RSS feed from them. There are no external dependencies beyond Emacs.
</p>

<p>
Today, I <a href="http://melpa-stable.milkbox.net/#/org-static-blog">released</a> version 1.1.0 of org-static-blog, which introduces two new features: <a href="http://bastibe.de/2018-03-17-speeding-up-org-static-blog.html">speed</a>, and tags. You can now—optionally—add <code>#+filetags:</code> to your *.org files, <code>(setq org-static-blog-enable-tags t)</code>, and org-static-blog will add tag links to every blog post, create tag indices, and add <code>&lt;category&gt;</code> tags to the RSS feed.
</p>

<p>
<b>Update:</b>
</p>

<p>
As <a href="https://github.com/kaushalmodi">Kaushal Modi</a> pointed out in the comments, org-mode uses <code>#+filetags:</code> to set tags for entire files. My first implementation used <code>#+tags:</code>. This is now deprecated. <code>#+tags:</code> still works, but issues a warning, and will be removed in the future. Sorry for the inconvenience.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-blog.html">blog</a> ]]></description>
  <category><![CDATA[blog]]></category>
  <link>https://bastibe.de/2018-03-22-org-static-blog-gets-tags.html</link>
  <guid>https://bastibe.de/2018-03-22-org-static-blog-gets-tags.html</guid>
  <pubDate>Thu, 22 Mar 2018 08:37:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Speeding up org-static-blog]]></title>
  <description><![CDATA[
<p>
Three years ago, I had enough of all the static site generators out there. Over the life of this blog, I had used <a href="http://bastibe.de/2012-07-18-blogging-with-pelican.html">Octopress, then Pelican</a>, then <a href="http://bastibe.de/2013-11-13-blogging-with-emacs.html">Coleslaw</a>, then <a href="http://bastibe.de/2014-05-07-speeding-up-org-publishing.html">org-mode</a>, and then wrote my own static site generator, <a href="https://github.com/bastibe/org-static-blog">org-static-blog</a>. Above all, org-static-blog is <i>simple</i>. It iterates over all *.org files in <code>org-static-blog-posts-directory</code>, and then exports all of these files to HTML. Simple is good. Simple is reliable. Simple means I can fix things.
</p>

<p>
However, simple can also mean inefficient. Most glaringly, org-static-blog exports every single blog post three times every time you publish: Once to render the HTML, then once to render the RSS feed, then once to render the Index and Archive pages.
</p>

<p>
Today, I finally tackled this problem: Now, org-static-blog only exports each post once, when the *.org file changes. The RSS feed, the Index page, and the Archive page simply read the already-rendered HTML instead of exporting again.
</p>

<p>
Thus, a full rebuild of this blog and all of its 85 posts used to take 2:12 min, and now takes 42 s. More importantly, if only one org file changed, the rebuild used to take 1:08 min, and now takes 1.5 s. Things like this are hugely satisfying to me!
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-org-mode.html">org-mode</a> <a href="https://bastibe.de/tag-emacs.html">emacs</a> <a href="https://bastibe.de/tag-blog.html">blog</a> ]]></description>
  <category><![CDATA[org-mode]]></category>
  <category><![CDATA[emacs]]></category>
  <category><![CDATA[blog]]></category>
  <link>https://bastibe.de/2018-03-17-speeding-up-org-static-blog.html</link>
  <guid>https://bastibe.de/2018-03-17-speeding-up-org-static-blog.html</guid>
  <pubDate>Sat, 17 Mar 2018 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Files and Processes]]></title>
  <description><![CDATA[
<p>
In the last few months, I have created three notable programming projects: <a href="https://github.com/bastibe/RunForrest">RunForrest</a> saves function call graphs to disk and runs them in parallel processes; <a href="https://github.com/bastibe/timeup">TimeUp</a> creates backups using rsync and keeps different numbers of hourly, daily, and weekly backups; and <a href="https://github.com/bastibe/jbof">JBOF</a>, which organizes large collections of data and metadata as structured, on-disk datasets.
</p>

<p>
These projects have one thing in common: They use Python to interact with external <i>things</i>, such as files, libraries, or processes. It surprised me that none of these projects were particularly hard to build, even though they accomplish "hard" tasks. This prompted some soul-searching about why I thought these tasks to be hard, and I have come up with two observations:
</p>

<ol class="org-ol">
<li><p>
Files and processes are considered "not part of the language", and are therefore not taught. Most programming classes and programming tutorials I have seen focus on the internals of a programming language, i.e. its data structures, and built-in functions and libraries. Files and processes are not part of this, and are often only mentioned in passing, as a thing that a particularly library can do. Worse, many curricula never formally explain files or processes, or their use in building programs.
</p>

<p>
I now believe that this is unfortunate and misguided, since the interaction with the computer's resources is the central benefit of programming, and you can not make much use of those resources without a thorough understanding of files and processes. In a way, the "inside" of a programming language is a mere sandbox, a safe place for toying with imaginary castles. But it is the "outside", that is, external programs, libraries, and files, that unlocks the true power of making the computer do work. And in Python in particular, using these building blocks to build useful programs is surprisingly simple.
</p></li>

<li><p>
However, such small and simple programs are much less popular than bloated behemoths. I built RunForrest explicitly because <a href="http://dask.pydata.org">Dask</a> was too confusing and unpredictable for the job. I build JBOF because <a href="http://www.h5py.org/">h5py</a> was too complex and slow. And this is surprising, since these tools certainly are vastly more mature than anything I can whip up. But they were developed by large organizations to solve large-organization problems. But I am not a large organization, and my needs are different as well.
</p>

<p>
I now believe that such small-scale solutions are often preferable to high-profile tools, but they lack the visibility and publicity of tools such as Dask and HDF. And even worse, seeing these big tools solve such mundane problems, we form the belief that these problems must be incredibly complex, and beyond our abilities. Thus forms a vicious cycle. Of course, this is not to say that these big tools do not serve a purpose. Dask and HDF were built to solve particular problems, but we should be aware that most big tools were built for big problems, and our own problems are often not big enough to warrant their use.
</p></li>
</ol>

<p>
In summary, we should teach people about files and processes, and empower them to tackle "hard" tasks without resorting to monolithic libraries. Not only is this incredibly satisfying, it also leads to better programs and better programmers.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <link>https://bastibe.de/2018-01-24-files-and-processes.html</link>
  <guid>https://bastibe.de/2018-01-24-files-and-processes.html</guid>
  <pubDate>Wed, 24 Jan 2018 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[How to set up rsnapshot instead of Time Machine]]></title>
  <description><![CDATA[
<p>
(This blog post was changed since my initial strategy of disabling the lockfile didn't work. Turns out, the lockfile is required, and backups have to be stacked.)
</p>

<p>
Yesterday, I wrote about how Time Machine has failed me. Time Machine keeps regular backups, going back as far as your hard drive space permits. In theory. In practice, every year or so it messes up somehow and has to start over, thereby deleting all your older backups. A backup that is not reliable is not a backup.
</p>

<p>
Luckily, there are alternatives. Probably the easiest is <a href="https://rsync.samba.org/">rsync</a>[1], a very cool tool that copies files and directories from one place to another. You could simply run this once a day, and have a new backup every day. You can even configure rsync so it doesn't need to copy unchanged files, and instead hard-links them from an older backup. <a href="http://rsnapshot.org/">rsnapshot</a> automates this process to keep a number of tiered copies, for example ten hourly backups, seven daily backups, four weekly backups, and a hundred monthly backups. Each backup is then simply a directory that contains your files. No fancy starfield-GUI, but utterly reliable and trivial to understand [2].
</p>

<p>
Setting up rsnapshot on macOS is not quite as straight-forward as I'd like, and I couldn't find a great guide online. So, without further ado, here's how to configure rsnapshot on macOS:
</p>


<ul class="org-ul">
<li><p>
Install rsnapshot
</p>

<pre class="example">
brew install rsnapshot
</pre></li>

<li><p>
Write the config file
</p>

<p>
You can copy a template from homebrew:
</p>
<pre class="example">
cp /usr/local/Cellar/rsnapshot/1.4.2/etc/rsnapshot.conf.default /usr/local/etc/rsnapshot.conf
</pre>

<p>
And then configure the new configuration file to your liking (preserve the tabs!):
</p>

<div class="org-src-container">
<pre class="src src-config">  config_version	1.2 # default
  verbose		2   # default
  loglevel	3   # default

  # this is where your backups are stored:
  snapshot_root	/Volumes/BBackup/Backups.rsnapshot/ # make sure this is writeable
  # prevent accidental backup corruption:
  lockfile	/Users/bb/.rsnapshot.pid
  # use this if you back up to an external drive:
  no_create_root	1   # don't back up if the external drive is not connected

  # configure how many tiers of backups are created:
  retain	hourly	10
  retain	daily	7   # dailies will only be created once 10 hourlies exist
  retain	weekly	4   # weeklies will only be created once 7 dailies exist
  retain	monthly	100 # monthlies will only be created once 4 weeklies exist

  # the list of directories you want to back up:
  backup	/Users/bb/Documents		localhost/
  backup	/Users/bb/eBooks		localhost/
  backup	/Users/bb/Movies		localhost/
  backup	/Users/bb/Music		localhost/
  backup	/Users/bb/Pictures		localhost/
  backup	/Users/bb/Projects		localhost/
  backup	/Users/bb/Projects-Archive		localhost/
</pre>
</div>

<p>
Instead of <code>localhost</code>, you can use remote machines as well. Check  <a href="https://download.samba.org/pub/rsync/rsync.html"><code>man rsync</code></a> for details
</p></li>

<li><p>
Make sure it works and create initial backup
</p>

<pre class="example">
rsnapshot -c /usr/local/etc/rsnapshot.conf hourly
</pre>

<p>
The first backup will take a while, but subsequent backups will be fast. A normal backup on my machine takes about two minutes and runs unnoticeably in the background.
</p></li>

<li><p>
Write launchd Agent
</p>

<p>
Next, we have to tell macOS to run the backups in regular intervals. Conceptually, you do this by writing a launchd agent script[3], which tells launchd when and how to run your backups. In my case, I create four files in <code>/Users/bb/Library/LaunchAgents/</code>, called <code>rsnapshot.{hourly,daily,weekly,monthly}.plist</code>. Apple's <a href="https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/ScheduledJobs.html">documentation</a> for these files is only mildly useful (as usual), but <a href="https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man5/launchd.plist.5.html"><code>man launchd.plist</code></a> and <a href="https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man5/plist.5.html#//apple_ref/doc/man/5/plist"><code>man plist</code></a> should give you an idea how this works.
</p>

<p>
Here is my hourly launchd agent (I'll explain the bash/sleep thing later):
</p>

<div class="org-src-container">
<pre class="src src-xml">  &lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
  &lt;plist version="1.0"&gt;
  &lt;dict&gt;
      &lt;key&gt;Label&lt;/key&gt;
      &lt;string&gt;rsnapshot.hourly&lt;/string&gt;
      &lt;key&gt;ProgramArguments&lt;/key&gt;
      &lt;array&gt;
          &lt;string&gt;/bin/bash&lt;/string&gt;
          &lt;string&gt;-c&lt;/string&gt;
          &lt;string&gt;sleep 0 &amp;&amp; /usr/local/bin/rsnapshot -c /usr/local/etc/rsnapshot.conf hourly&lt;/string&gt;
      &lt;/array&gt;
      &lt;key&gt;StartCalendarInterval&lt;/key&gt;
      &lt;dict&gt;
          &lt;key&gt;Minute&lt;/key&gt;
          &lt;integer&gt;0&lt;/integer&gt;
      &lt;/dict&gt;
  &lt;/dict&gt;
  &lt;/plist&gt;
</pre>
</div>

<p>
For the other four scripts, change the two occurrences of <code>hourly</code> to <code>{daily,weekly,monthly}</code> and change the <code>&lt;dict&gt;</code> portion at the end to
</p>

<ul class="org-ul">
<li><p>
daily:
</p>
<div class="org-src-container">
<pre class="src src-xml">    &lt;key&gt;Minute&lt;/key&gt;
    &lt;integer&gt;0&lt;/integer&gt;
    &lt;key&gt;Hour&lt;/key&gt;
    &lt;integer&gt;0&lt;/integer&gt;
</pre>
</div></li>
<li><p>
weekly:
</p>
<div class="org-src-container">
<pre class="src src-xml">    &lt;key&gt;Minute&lt;/key&gt;
    &lt;integer&gt;0&lt;/integer&gt;
    &lt;key&gt;Hour&lt;/key&gt;
    &lt;integer&gt;0&lt;/integer&gt;
    &lt;key&gt;Weekday&lt;/key&gt;
    &lt;integer&gt;1&lt;/integer&gt;
</pre>
</div></li>
<li><p>
monthly:
</p>
<div class="org-src-container">
<pre class="src src-xml">    &lt;key&gt;Minute&lt;/key&gt;
    &lt;integer&gt;0&lt;/integer&gt;
    &lt;key&gt;Hour&lt;/key&gt;
    &lt;integer&gt;0&lt;/integer&gt;
    &lt;key&gt;Day&lt;/key&gt;
    &lt;integer&gt;1&lt;/integer&gt;
</pre>
</div></li>
</ul>

<p>
However, <code>rsnapshot</code> can only ever run one backup at a time without stepping on its own toes. This is a problem when the computer wakes up, and more than one backup was scheduled during its sleep, since launchd will then happily launch all missed backups at the same time. But only one of them will succeed.
</p>

<p>
To fix this, I delay the later backup tiers using the <code>sleep 0</code> directive. I use <code>sleep 900</code> (15 minutes later) for daily, <code>sleep 1800</code> (30 minutes), and <code>sleep 2700</code> (45 minutes) for the lower tiers[4]. It seems that there should be a more elegant solution than this, but I haven't found one.
</p>

<p>
From the documentation, you might think that <code>&lt;key&gt;Program&lt;/key&gt;</code> would be more succinct than supplying the binary as the first argument of <code>&lt;key&gt;ProgramArguments&lt;/key&gt;</code>, but this apparently uses a different syntax and does not in fact work as expected.
</p></li>

<li><p>
Load launchd agents
</p>

<pre class="example">
launchctl load ~/Library/LaunchAgents/rsnapshot.*
</pre></li>

<li><p>
Test launchd agent
</p>

<pre class="example">
launchctl start rsnapshot.hourly
</pre>

<p>
If it doesn't work, Console.app might show a relevant error message.
</p></li>

<li><p>
Remove backup directory from Spotlight
</p>

<p>
Go to System Preferences → Spotlight → Privacy → Add your <code>snapshot_root</code> directory from earlier
</p></li>

<li><p>
Disable TimeMachine and delete your existing backup (if you want)
</p>

<p>
Start Time Machine, right-click any directory you want to delete, and select "delete all backups of $dir"
</p></li>
</ul>

<p>
[1] rsync is one of those reliable tools <a href="http://bastibe.de/2017-12-28-dropbox-timemachine-is-useless.html">I talked about</a>. It is rock solid, incredibly versatile, and unapologetically single-minded. A true gem!
</p>

<p>
[2] This works great for local backups. If you need encrypted backups or compressed backups (maybe on an untrusted remote machine), <a href="https://www.reddit.com/r/linux/comments/42feqz/i_asked_here_for_the_optimal_backup_solution_and/czbeuby/">this post</a> recommends <a href="https://www.borgbackup.org/">Borg</a> instead of rsnapshot, but you will lose the simplicity of simple directories.
</p>

<p>
[3] I use launchd instead of cron since launchd will re-schedule missed backups if the computer was asleep.
</p>

<p>
[4] This will fail if the hourly backup takes longer than 15 minutes. This is rather unlikely, though, or at least should not happen often enough to be of concern.
</p>

<div id="outline-container-org2a8f6a2" class="outline-2">
<h2 id="org2a8f6a2">Caveats</h2>
<div class="outline-text-2" id="text-org2a8f6a2">
<p>
The configuration file of rsnapshot says that you might experience data corruption if you run several copies of rsnapshot at the same time (and you can use the lockfile to prevent this). This is a problem if your computer is asleep while rsnapshot is scheduled to run, since launchd will then re-schedule all missed tasks at once when the computer wakes up. If you enable the lockfile, only one of them will run.
</p>

<p>
On the other hand, only the hourly task will actually create a new backup. All higher-level backup tiers merely copy existing backups around, so <i>in theory</i>, they shouldn't step on each other's toes when run concurrently. I have opened <a href="https://github.com/rsnapshot/rsnapshot/issues/200">an issue</a> asking about this.
</p>

<p>
There are other possible solutions: ① You could modify the launchd entry such that backups only trigger after a few minutes or, better yet, only once all other instances of rsnapshot have finished. I am not sure if launchd supports this, though. ② You could schedule the hourly task using cron instead of launchd, since cron will <i>not</i> reschedule missed tasks. This would only work for two tiers of backups, though. ③ You could just ignore the issue and hope for the best. After all, if a daily or hourly backup gets corrupted every now and then, you still have enough working backups&#x2026;
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-backup.html">backup</a> <a href="https://bastibe.de/tag-macos.html">macos</a> ]]></description>
  <category><![CDATA[backup]]></category>
  <category><![CDATA[macos]]></category>
  <link>https://bastibe.de/2017-12-29-rsnapshot-on-macos.html</link>
  <guid>https://bastibe.de/2017-12-29-rsnapshot-on-macos.html</guid>
  <pubDate>Fri, 29 Dec 2017 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Dropbox deleted my pictures and Time Machine didn't backup]]></title>
  <description><![CDATA[
<p>
Dropbox deleted some of my favorite photos. Have you looked at all your old pictures lately and checked if they are still there? I have, and they were not. Of course Dropbox denies it is their fault, but no other program routinely accessed my pictures. <a href="https://www.dropboxforum.com/t5/Missing-files-and-folders/Randomly-deleted-files-and-folders/td-p/203952">I am not alone with this problem</a>. It must have happened some time between the summer of 2015, when I put my pictures on Dropbox, and the summer of 2016, when Time Machine last corrupted its backups and had to start over, thereby deleting my last chance of recovering my pictures. The pictures are gone for good.
</p>

<p>
So, what have I learned? Dropbox loses your data, and Time Machine can't restore it. These programs are obviously no good for backups. Let me repeat this: <b>Dropbox and Time Machine are not a backup!</b> A true backup needs to be reliable, keep an infinite history, and <i>never</i>, <i>never</i>, <i>never</i> accidentally delete files.
</p>

<p>
From now on, I will use <a href="http://rsnapshot.org/">rsnapshot</a> for backups. <a href="https://rayed.com/wordpress/?p=1693">Here</a>'s a tutorial on how to set it up on a Mac. I have used rsnapshot for years at work, and it has never let me down. For syncronizing things between computers, I now use <a href="https://syncthing.net/">syncthing</a>. Both of these programs are not as user-friendly as Dropbox or Time Machine, but that is a small price to pay for a working backup.
</p>

<p>
A few years ago, I had high hopes that <a href="http://bastibe.de/2009-03-14-get-a-mac.html">Apple</a> and <a href="http://bastibe.de/2009-03-28-synchronisieren-von-google.html">Dropbox</a> and Google and Amazon would lead us to a bright future of computers that "just work", and could solve our daily chores ever more conveniently and reliably. But I was proven wrong. <a href="http://bastibe.de/2012-07-09-apple-is-failing-me.html">So</a>. <a href="http://bastibe.de/2012-11-01-apple-tv.html">Many</a>. <a href="http://bastibe.de/2015-10-16-finder-woes.html">Times</a>. It seems that for-profit software inevitably becomes less dependable as it adds ever more features to attract ever more users. In contrast, free software can focus on <a href="http://bastibe.de/2017-10-24-the-long-game.html">incremental improvements and steadily increasing reliability</a>.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-backup.html">backup</a> ]]></description>
  <category><![CDATA[backup]]></category>
  <link>https://bastibe.de/2017-12-28-dropbox-timemachine-is-useless.html</link>
  <guid>https://bastibe.de/2017-12-28-dropbox-timemachine-is-useless.html</guid>
  <pubDate>Thu, 28 Dec 2017 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Books of 2017]]></title>
  <description><![CDATA[
<p>
In late 2016, I took a short ferry flight to a small island in the area, and rekindled my love for aviation. Shortly afterwards, I started training for a pilot's license, and reading about aviation. From a literary perspective, aviation exists in the perfect goldilocks time frame of being just old enough to be thoroughly romanticized, but young enough for first-hand reports and thorough documentation to be available. What is more, powered flight has provided human observers with an unprecedented view of our world and our struggles, and is often as philosophical as it is exhilarating.
</p>

<div id="outline-container-orged0b4a2" class="outline-2">
<h2 id="orged0b4a2">Aviation Reading List</h2>
<div class="outline-text-2" id="text-orged0b4a2">
<p>
Out of a long list of fascinating books on aviation I have read over the last two years, my favorites are:
</p>


<figure id="org1fe61bd">
<img src="https://images.gr-assets.com/books/1348443108l/533779.jpg" alt="533779.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<ul class="org-ul">
<li><a href="https://www.goodreads.com/book/show/533779.Fate_Is_the_Hunter">Fate is the Hunter</a> by Ernest K. Gann, a gripping memoir of the early days of aviation. It has been only a little more than a hundred years since humans first took to the skies in Kitty Hawk in 1905, yet today aviation feels as mundane as horse-drawn carriages must have felt to the Wright Brothers. Gann lived through these early days, and tells his tales from a time when aviation was still young, dangerous, and perhaps more interesting. If you want to read more like this, <a href="https://www.goodreads.com/book/show/400492.Flight_of_Passage">Flight of Passage</a> by Rinker Buck, and <a href="https://www.goodreads.com/book/show/571406.The_Spirit_of_St_Louis">The Spirit of St. Louis</a> by Charles Lindbergh are easy recommendations as well.</li>
</ul>


<figure id="org195ed95">
<img src="https://images.gr-assets.com/books/1503014062l/36060428.jpg" alt="36060428.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<ul class="org-ul">
<li><a href="https://www.goodreads.com/book/show/612456.Carrying_the_Fire">Carrying the Fire</a> by Michael Collins, one of the few first-hand accounts of an Apollo astronaut's voyage to the Moon. Most astronauts have published books later on, but most had them ghost-written, and none are as visceral and engaging as Michael Collins' journey on Apollo 8. It is humbling that Apollo's achievements have not been surpassed, despite our much more advanced technology and science. Other accounts worth reading are <a href="https://www.goodreads.com/book/show/271540.The_Last_Man_on_the_Moon">The Last Man on the Moon</a> by Gene Cernan on Apollo 17, and <a href="https://www.goodreads.com/book/show/2323178.How_Apollo_Flew_to_the_Moon?ac=1&amp;from_search=true">How Apollo Flew to the Moon</a> by W. David Woods, for a more technical view.</li>
</ul>


<figure id="orgc090fb2">
<img src="https://images.gr-assets.com/books/1458495570l/26210477.jpg" alt="26210477.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<ul class="org-ul">
<li><a href="https://www.goodreads.com/book/show/22926778-skyfaring">Skyfaring</a> by Mark Vanhoenacker is a more modern, and more philosophical account of how aviation has changed our perception of the world. If you yearn to fly like I do, then this book is a balm for the soul. The almost spiritual feeling of cutting your bonds with the ground is what this book is about, despite being written in today's un-romantic days of routine commercial airliners. I love it dearly. A more grounded account of aviation's history is <a href="https://www.goodreads.com/book/show/1492469.Turbulent_Skies?from_search=true">Turbulent Skies</a> by T. A. Heppenheimer, and maybe <a href="https://www.goodreads.com/book/show/107298.Slide_Rule?from_search=true">Slide Rule</a> by Nevil Chute for some history on airships.</li>
</ul>

<br>
</div>
</div>

<div id="outline-container-org18fc27e" class="outline-2">
<h2 id="org18fc27e">Fiction Reading List</h2>
<div class="outline-text-2" id="text-org18fc27e">
<p>
But as much as I love aviation, my first love is still Science Fiction. We live in strange times of unprecedented prosperity, and yet we are strangely unsatisfied, as if the future didn't turn out to be the utopia it was meant to be. Or is this just a reflection of ourselves, how we do not live up to the future we built?
</p>


<figure id="orge8aacd7">
<img src="https://images.gr-assets.com/books/1457598923l/29475447.jpg" alt="29475447.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<ul class="org-ul">
<li><a href="https://www.goodreads.com/series/170872-wayfarers">A Closed and Common Orbit</a> by Becky Chambers describes a more distant future, when space travel is as mundane as airliners are today, and humanity is just one of several alien species. Yet, with all its technological marvels, we still yearn for meaning and love, regardless of what strange world we live in. A Closed and Common Orbit is the second book in the series, and the first book I read. I think I prefer it in this order.</li>
</ul>

<br><br>


<figure id="org3b53dbd">
<img src="https://images.gr-assets.com/books/1328341796l/8605343.jpg" alt="8605343.jpg" style="float:left;margin:5px;margin-right:20px" width="150px">

</figure>

<ul class="org-ul">
<li><a href="https://www.goodreads.com/series/50764-laundry-files">The Laundry Files</a> Series by Charles Stross is closer to home. Did you ever notice how computer programming is eerily similar to the arcane incantations we use to describe magic in fiction? Where is the difference between invoking a function that effects a robot, and invoking a magic spell that affects a demon? According to Charles Stross, this difference is really only playing with semantics, and we should be very careful with our incantations, lest the ghost in the machine really does have our demise in mind. These books have made me laugh out loud so many times, like when a weaponized PowerPoint turned people into zombies, or when a structured cabling project turned out to create an inadvertent summoning grid for an elder horror.</li>
</ul>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-books.html">books</a> ]]></description>
  <category><![CDATA[books]]></category>
  <link>https://bastibe.de/2017-12-20-books-of-2017.html</link>
  <guid>https://bastibe.de/2017-12-20-books-of-2017.html</guid>
  <pubDate>Wed, 20 Dec 2017 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[PyEnv is the new Conda]]></title>
  <description><![CDATA[
<p>
How to install Python? If your platform has a package manager, you might be tempted to use that to install Python. But I don't like that. That version is often outdated, and you risk messing with an integral part of your operating system. Instead, I like to install a separate Python in my home directory. I used to use <a href="https://conda.io/miniconda.html">Anaconda</a> (or <a href="http://winpython.github.io/">WinPython</a>, or <a href="https://www.enthought.com/product/enthought-python-distribution">EPD</a>) to do this. But now there is a better way: <a href="https://github.com/pyenv/pyenv">PyEnv</a>
</p>

<p>
The thing is: PyEnv installs (any version of) Python. That's all it does.
</p>

<p>
So why would I choose PyEnv over the more popular Anaconda? Because Anaconda is a Python distribution, a package manager, an environment manager, and a platform for paid packages. In the past, they once did <a href="https://stackoverflow.com/questions/38524856/anaconda-3-for-linux-has-no-ensurepip#39114277">break pip</a> because they wanted to promote conda instead. Some features of conda <a href="https://anaconda.org/">require a login</a>, some require a <a href="https://www.anaconda.com/enterprise/">paid subscription</a>. When you install packages through conda, you get binaries and source code from anaconda's servers, <i>not</i> the official packages from PyPi, which might or might not be up-to-date and feature-complete. For every package you install, you have to make a choice of using pip or conda, and the same goes for specifying your dependencies.
</p>

<p>
As an aside, many of these complaints are just as true for package-manager-provided Python packages (which often <a href="https://askubuntu.com/questions/879437/ensurepip-is-disabled-in-debian-ubuntu-for-the-system-python#897004">break pip</a>, too!). Just like Anaconda, package managers want to be the true and only source of packages, and don't like to interact with Python's own package manager.
</p>

<p>
In contrast, with PyEnv, you install a Python. This can be a version of CPython, PyPy, IronPython, Jython, Pyston, stackless, miniconda, or even Anaconda. It downloads the sources from the official repos, and compiles them on your machine [1]. Plus, it provides an easy and transparent way of switching between installed versions (including any system-installed versions). After that, you use Python's own venv and pip.
</p>

<p>
I find this process much simpler, and easier to manage, because it relies on small, orthogonal tools (pyenv, venv, pip) instead of one integrated conda that kind of does everything. I also like to use these official tools and packages instead of conda's parallel universe of mostly-open, mostly-free, mostly-standard replacements.
</p>

<p>
Mind you, conda solved real problems back in the day (binary package distributions, Python version management, and environment management), and arguably still does (MKL et al, paid packages). But ever since wheels became <a href="https://pythonwheels.com/">ubiquitous and painless</a>, and virtualenv was <a href="https://docs.python.org/3/library/venv.html">integrated into Python</a>, and the development of PyEnv, these issues now have better solutions, and conda is no longer needed for my applications.
</p>

<p>
[1] the downside of compilation is: no Windows support.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-python.html">python</a> ]]></description>
  <category><![CDATA[python]]></category>
  <link>https://bastibe.de/2017-11-20-pyenv.html</link>
  <guid>https://bastibe.de/2017-11-20-pyenv.html</guid>
  <pubDate>Mon, 20 Nov 2017 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Installing Emacs on Windows]]></title>
  <description><![CDATA[
<p>
The <a href="https://www.gnu.org/software/emacs/download.html#windows">official website</a> states that you need to download Emacs from a <a href="http://ftpmirror.gnu.org/emacs/windows">nearby GNU mirror</a>. However, this does not install gnutls, which is required for installing packages from <a href="http://melpa-stable.milkbox.net/#/">melpa</a> or <a href="https://marmalade-repo.org/">marmalade</a>. The <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs-gnutls/Help-For-Users.html">documentation</a> says that this can be obtained from <a href="https://sourceforge.net/projects/ezwinports/files/">ezwinports</a>.
</p>

<p>
However, I have found that this does not work any more: As of Emacs 25, Emacs is available in 64 bit, but ezwinport only supplies 32 bit binaries. I had to search a bit, but the (in retrospect, obvious) solution is to download the required binaries from <a href="https://gnutls.org/download.html">GnuTLS's website</a>, directly. Then unpack all <code>*.dll</code> from the <code>bin</code> directory to your Emacs's <code>bin</code> directory, and you are good to go.
</p>

<p>
This situation is really a bit sad. Installing Emacs should not be this hard. But there is <a href="https://lists.gnu.org/archive/html/emacs-devel/2017-10/msg00805.html">talk</a> about providing a Windows installer for Emacs in one of the next versions, which will hopefully fix these issues.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-emacs.html">emacs</a> <a href="https://bastibe.de/tag-windows.html">windows</a> ]]></description>
  <category><![CDATA[emacs]]></category>
  <category><![CDATA[windows]]></category>
  <link>https://bastibe.de/2017-11-19-emacs-on-windows.html</link>
  <guid>https://bastibe.de/2017-11-19-emacs-on-windows.html</guid>
  <pubDate>Sun, 19 Nov 2017 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[The Long Game]]></title>
  <description><![CDATA[
<p>
Here's a thing I do: I write open source libraries that solve my problems. <i>Bad</i> libraries. And then, over the course of a year or two, I slowly improve them, until they are not so bad any more.
</p>

<p>
I have gone through this pattern a few times now. <a href="https://github.com/bastibe/PySoundFile">SoundFile</a> started out buggy and slow. <a href="https://github.com/bastibe/transplant">Transplant</a> crashed and froze very often. <a href="https://github.com/bastibe/org-journal">Org-Journal</a> deleted journal entries every now and then. But then users found errors, and errors were fixed. And slowly, over time, these libraries transformed from buggy prototypes into dependable tools. After a year or so, I saw Github Issues gradually drying up, and feedback changing from "X is broken" to "How can I do X?". It is an oddly gratifying process.
</p>

<p>
Interestingly though, I rarely hear people talking about this, that building a thing is only the beginning, and the meat of open source development is sticking with it for a long time, and gradually, slowly, weeding out the bugs. All great open source libraries I know evolved this way, yet it is rarely written about.
</p>

<p>
Playing the long game means anticipating and managing the amount of maintenance I am going to do on a project. When releasing a new library, the first few months and users will shake out bugs, and create work for the maintainers. This can be a dangerous source of stress and anxiety. I've had my brush with burnout in the past, and my only defense to this is to be honest about my availability. Often, this means stating outright that I probably won't have the time to work on a thing.
</p>

<p>
However, I have also learned that it is OK to defer issues to the future. There have been many problems that I didn't have the time to address when they first came up, but <i>did</i> address a few months later, probably in response to a separate bug report. Important problems have a way of getting fixed eventually. Other times, a solution just takes a long time to mature. There have been multiple issues that lay dormant for months until I stumbled upon a good solution.
</p>

<p>
And good solutions are important for open source software: If a bug fix adds too much complexity, it will inevitably lead to <i>more</i> bugs. This can easily snowball into a situation where each hour I invest into a project creates <i>more hours</i> of future maintenance burden. A situation like this feels hopeless and terrible. It feels like work. It is therefore important for my sanity to control the complexity of my projects, even if that means not adding features or not addressing problems. Open source development is not beholden to the dollar sign, and gives you the freedom to do it <i>right</i>.
</p>

<p>
This is not universally understood by programmers or users. And it doesn't just involve technical questions: Some users have expected me to provide commercial-grade support, and got surprisingly unpleasant when I didn't. But it is crucial to realize that publishing open source software <i>does not imply an obligation to fix every issue right now</i>. Quite on the contrary, many open source developers necessarily work on their own schedule, and part of the enjoyment of open source development is derived from this exact freedom!
</p>

<p>
At this point, my Github lists a bunch of open source projects. Some of them have gotten attention, which lead to bug reports, and, over time, let them grow to maturity. Some turned out to be <a href="https://github.com/bastibe/annotate.el">useful</a> <a href="https://github.com/bastibe/twilight">to</a> <a href="https://github.com/bastibe/org-static-blog">me</a>, but not to others. Some are useful <a href="https://github.com/bastibe/Violinplot-Matlab">to</a> <a href="https://github.com/bastibe/lunatic-python">others</a>, but not to me. Some turned out to be not useful <a href="https://github.com/bastibe/MatlabCodeAnalyzer">at all</a>, and are now largely abandoned. And some of them, like <a href="https://github.com/bastibe/RunForrest">RunForrest</a> and <a href="https://github.com/bastibe/SoundCard">SoundCard</a>, are still new and raw and terrible, but will mature over time.
</p>

<p>
That's a thing I do: I write open source libraries. <i>Good</i> libraries, but as a <a href="https://en.wikiquote.org/wiki/Piet_Hein">wise man</a> once said "When you feel how depressingly / slowly you climb, / it's well to remember that / Things Take Time". Working on open source grants you this freedom, and is joyful for it.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <link>https://bastibe.de/2017-10-24-the-long-game.html</link>
  <guid>https://bastibe.de/2017-10-24-the-long-game.html</guid>
  <pubDate>Tue, 24 Oct 2017 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Multi-Font Themes in Emacs]]></title>
  <description><![CDATA[
<p>
Traditionally, text editor themes are all about colors, right? In programming, we use color to tell variables from type declarations, comments, or strings. However, any other text document uses typography instead of color to distinguish between headlines, list items, and keywords. I think that our current approach to highlighting code is misguided.
</p>

<p>
I think that color themes are an accident of history. Terminal text editors are unable to switch fonts. All they can do is switch colors, so colors is all we use. But in todays graphical world, we are no longer bound by the shackles of terminals, and Emacs can switch fonts just as easily as colors<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>.
</p>

<p>
It all started about a year ago, when I fell in love with a font called <a href="https://www.fsd.it/shop/fonts/pragmatapro/">PragmataPro</a>. One of the coolest features of Pragmata was its native bold and italic letters, and its wide support for unicode symbols. I had to find a use for these features! And so, down the rabbit hole I went. <b>Keywords</b> should be bold! <i># Comments</i> should be italic! And while we're at it, why not add some <span class="underline">underlines</span>? And so on.
</p>

<p>
The logical next step was then to get rid of colors altogether. At first, as an experiment. Do I really <i>need</i> colors in code? The very pretty <a href="https://github.com/maio/eink-emacs">eink theme</a> seemed to claim otherwise. After a few months of this lunacy, I realized that while I didn't strictly <i>need</i> colors, the stylistic variations of just one font aren't quite sufficient for source code. In particular, it wasn't always easy to distinguish between italic and roman type in PragmataPro, which lead to some confusion.
</p>

<p>
But then, inspiration hit me: Who says that I could only use one single font? No one!
</p>


<figure id="org8c82e7f">
<img src="http://bastibe.de/static/2017-09/color%20theme.png" alt="color%20theme.png">

</figure>

<p>
The tricky bit is to find fonts that work well together. In this example, I'm using PragmataPro for all regular code, <a href="https://be5invis.github.io/Iosevka/">Iosevka</a> Slab<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup> for strings, and oblique<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup> Iosevka for comments. <a href="http://font.ubuntu.com/">Ubuntu Mono</a> and <a href="http://input.fontbureau.com/">InputCompressed</a> work well, too. You can find my current theme <a href="https://github.com/bastibe/.emacs.d/blob/master/lisp/my-eink-theme.el">on Github</a>. The only downside is that while these fonts share the character width, the heights differ slightly, which sometimes leads to uneven line heights.
</p>

<p>
Still, I love the look of this! (Of course it won't work in a terminal, or most other text editors.)
</p>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
: Can other text editors do this? I honestly have no idea.
</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
: I just love the look of the slab-serif characters in Iosevka! Look at the beautiful <code>"}"</code> in the screenshot!
</p></div></div>

<div class="footdef"><sup><a id="fn.3" class="footnum" href="#fnr.3" role="doc-backlink">3</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
: not to be confused with <i>italic</i>, which changes glyphs in addition to slanting.
</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-emacs.html">emacs</a> ]]></description>
  <category><![CDATA[emacs]]></category>
  <link>https://bastibe.de/2017-09-19-multi-font-themes.html</link>
  <guid>https://bastibe.de/2017-09-19-multi-font-themes.html</guid>
  <pubDate>Tue, 19 Sep 2017 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[EuroScipy 2017]]></title>
  <description><![CDATA[
<p>
The second conference I attended this year was the <a href="https://www.euroscipy.org/2017/">EuroScipy 2017</a> in Erlangen. I gave a <a href="https://www.youtube.com/watch?v=mc8ru37dwf8">Talk about Audio in Python</a> and a <a href="https://youtu.be/qTgk2DUM6G0?t=10m15s">Lightning Talk about my Python/Matlab bridge</a>.
</p>

<p>
My most striking impression of EuroScipy is that every person I talked to was working on something interesting, and could talk about his/her topic clearly and with enthusiasm. This mirrors my feelings from last year's Chaos Communication Congress, where the short scientific section stood out for its clarity and passion. I also enjoyed the fact that attendees were international and diverse, and exuded a heart-warming sense of community.
</p>

<p>
Even though each scientific discipline has their own data sets, features, and models, everyone seemed to use a common set of methods (statistics, signal processing, machine learning) for working with that data. And, absolutely everybody used <a href="http://jupyter.org/">Jupyter Notebooks</a> for tutorials and teaching, and almost all data analyses were done in <a href="http://pandas.pydata.org/">Pandas</a>. This is particularly heartening since these technologies are geared towards reproducible research and open data.
</p>

<p>
The hot topic of the conference clearly was machine learning and neural networks. However, the current confusion of competing frameworks and network architectures does not seem to be a good long-term solution. I hope that this ecosystem will eventually reach its NumPy moment, and collapse into a single, unified package. Then, neural networks might find their place as just another machine learning method with a few reusable parametrized prototype implementations in scikit-learn. Tools like <a href="https://keras.io/">Keras</a> look like good steps towards this goal.
</p>

<p>
Finally, there was a lot of talk about “the reproducibility crisis” in science, and possible steps to improve the scientific process. In particular, I learned that it is absolutely necessary to not look at your test data before the final evaluation, to avoid overfitting your brain. You need to split your data into a development set for training, a validation set for parameter tuning, and a totally separate evaluation set for the final evaluation. In a similar way, it is important to state your hypotheses <i>in writing</i> before you test them, to avoid “HARKing” (Hypothesis After the Results are Known; aka “Noise Mining”, “P-Hacking”, or “Procedural Overfitting”). I dearly hope that <a href="https://cos.io/rr/">Registered Reports</a> will catch on, and absolve us from these all too human biases.
</p>

<p>
In conclusion, EuroScipy 2017 was a ton of fun, and educational in many ways that I did not expect. If you are a scientific programmer, or if you maintain a scientific Python module, or if you are plain interested in scientific Python, I can highly recommend going to EuroScipy next year.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-event.html">event</a> ]]></description>
  <category><![CDATA[event]]></category>
  <link>https://bastibe.de/2017-09-01-euroscipy.html</link>
  <guid>https://bastibe.de/2017-09-01-euroscipy.html</guid>
  <pubDate>Fri, 01 Sep 2017 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Web Audio Conference and JavaScript]]></title>
  <description><![CDATA[
<p>
I am not much of a web programmer. I have written the odd website, I have supervised a few student projects, but I have never worked on any nontrivial JavaScript code base. Nevertheless, last week, I attended the <a href="http://wac.eecs.qmul.ac.uk/">Web Audio Conference 2017</a> in London. To put it succinctly: The web is home to fascinating people, but the technology is full of problems.
</p>

<p>
Those people sure were amazing, though. I talked to a musician/programmer, who spent the last few years writing his own sequencer web app, and did an amazing live performance in his web browser! I witnessed another guy live coding a synthesizer in a web app on stage as a music piece. We attended a gastronomical concert with smartphone-synchronized distributed olfactory and audible experiences. And we played the piano, with each participant controlling one key from his smartphone. It was all truly inspiring!
</p>

<p>
All of this was built on JavaScript, however. One musical performance reached its climax when the musician queued too many samples and synthesizers and JavaScript crashed. The crowd cheered, but this still highlights how JavaScript, garbage collection pauses, and heap exhaustion are real problems. And there was not a single talk that did not long for dedicated Audio Workers to fix some of these problems.
</p>

<p>
But more than that, I learned that most of these apps have to pile frameworks upon frameworks just to get a simple demo app going. This is inescapable, since JavaScript is just not usable as an application platform without these frameworks. I take this as a warning: One should build a project from scratch every now and then, just to keep a realistic feel of how deep one's technology stack really is.
</p>

<p>
All of these people are using JavaScript as an application platform. I would wager that an application platform is basically something like ①: layout, ②: widgets, ③: data bindings, and ④: event handling. If you think about it, JavaScript without libraries currently covers at most ① (CSS) and maybe ② (using HTML Custom Elements), though not at all at the same level as true GUI frameworks such as Qt or Cocoa. For ③ and ④, you have to add something like Ember, React, or Angular. It is strange to me that the JavaScript ecosystem does not seem to gravitate towards integrated frameworks but seems to prefer this wild west of codependent libraries.
</p>

<p>
Then again, limitations breed genius, and the limits of the platform no doubt fueled the amazing feats these web audio people pulled off at WAC. It is truly inspiring what miracles dedicated people can pull off if they set their mind on them. And let's not forget that the Web Audio API itself is the work of a single person (per browser) as well.
</p>

<p>
So, in summary, I learned a lot at WAC. I learned that web technologies are not ideal as an application platform. I learned that deep framework stacks are not desirable, yet often necessary. But above all, I learned that all this does not stop people from writing astonishing applications with those technologies. More power to the crazy ones!
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-event.html">event</a> ]]></description>
  <category><![CDATA[event]]></category>
  <link>https://bastibe.de/2017-08-29-wac-and-javascript.html</link>
  <guid>https://bastibe.de/2017-08-29-wac-and-javascript.html</guid>
  <pubDate>Sun, 27 Aug 2017 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Audio APIs, Part 3: WASAPI / Windows]]></title>
  <description><![CDATA[
<p>
This is part three of a three-part series on the native audio APIs for Windows, Linux, and macOS. This third part is about WASAPI on Windows.
</p>

<p>
It has long been a major frustration for my work that Python does not have a great package for playing and recording audio. My first step to improve this situation was a small contribution to <a href="https://people.csail.mit.edu/hubert/pyaudio/">PyAudio</a>, a CPython extension that exposes the C library <a href="http://www.portaudio.com/">PortAudio</a> to Python. However, I soon realized that PyAudio mirrors PortAudio's C API a bit too closely for comfort. Thus, I set out to write <a href="https://github.com/bastibe/PySoundCard">PySoundCard</a>, which is a higher-level wrapper for PortAudio that tries to be more pythonic and uses NumPy arrays instead of untyped <code>bytes</code> buffers for audio data. However, I then realized that PortAudio itself had some inherent problems that a wrapper would not be able to solve, and a truly great solution would need to do it the hard way:
</p>

<p>
Instead of relying on PortAudio, I would have to use the native audio APIs of the three major platforms directly, and implement a simple, cross-platform, high-level, NumPy-aware Python API myself. This effort resulted in <a href="https://github.com/bastibe/Python-Audio">PythonAudio</a>, a new pure-Python package that uses <a href="http://cffi.readthedocs.io/en/latest/">CFFI</a> to talk to <a href="https://www.freedesktop.org/wiki/Software/PulseAudio/">PulseAudio</a> on Linux, <a href="https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html">Core Audio</a> on macOS, and <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd371455(v=vs.85).aspx">WASAPI</a>[1] on Windows.
</p>

<p>
This series of blog posts summarizes my experiences with these three APIs and outlines the basic structure of how to use them. For reference, the singular use case in PythonAudio is block-wise playing/recording of <code>float</code> data at arbitrary sampling rates and block sizes. All available sound cards should be listable and selectable, with correct detection of the system default sound cards (a feature that is very unreliable in PortAudio).
</p>

<p>
[1]: WASAPI is part of the Windows <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd370784(v=vs.85).aspx">Core Audio</a> APIs. To avoid confusion with the macOS API of the same name, I will always to refer to it as WASAPI.
</p>


<hr>

<div id="outline-container-orgf320333" class="outline-2">
<h2 id="orgf320333">WASAPI</h2>
<div class="outline-text-2" id="text-orgf320333">
<p>
WASAPI is one of several native audio libraries in Windows. PortAudio actually <a href="http://portaudio.com/docs/v19-doxydocs/compile_windows.html">supports five of them</a>: <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd743883(v=vs.85).aspx">Windows Multimedia (MME)</a>, the first built-in audio API for Windows 3.1x; <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ee416960(v=vs.85).aspx">DirectSound</a>, the audio subsystem of DirectX for Windows 95;  <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/stream/kernel-streaming">Windows Driver Model / Kernel Streaming (WDM/KS)</a>, the improved audio system for Windows 98; <a href="https://en.wikipedia.org/wiki/Audio_Stream_Input/Output">ASIO</a>, a third-party API developed by Steinberg to make pro audio possible on Windows; and finally, <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd370784(v=vs.85).aspx">Windows Audio Session API (WASAPI)</a>, introduced in Windows Vista to bring a modern audio API to Windows.
</p>

<p>
In other words, audio on Windows has a long and troubled history, and has had a lot of opportunity for experimentation. It should then be no surprise that WASAPI is a clean and well-documented audio API that avoids many of the pitfalls of its predecessors and brethren. After having experienced the audio APIs of Windows, Linux, and macOS, I am beginning to understand why some programmers love Windows.
</p>

<p>
But let's take a step back, and give an overview over the API. First of all, this is a cross-language API that is meant to be used from C#, with a solid bridge for C++, and a somewhat funky bridge for C. This is crucial to understand. The whole API is designed for a high-level, object-oriented runtime, but I am accessing it from a low-level language that has no concept of objects, methods, or exceptions.
</p>

<p>
Objects are implemented as pointers to opaque structs, with an associated list of function pointers to methods. Every method accepts the object pointer as its first argument, and returns an error value if an exception occurred. Both inputs and outputs are function arguments, with outputs being implemented as pointer-to-pointer values. While this looks convoluted to a C programmer, it is actually a very clean mapping of object oriented concepts to C that never gave me any headaches.
</p>

<p>
However, there are a few edge cases that did take me a while to understand: Since the C API is inherently not polymorphic, you sometimes have to manually specify types as cryptic UUID structs. Figuring out how to convert the UUID strings from the header files to such structs was not easy.  Similarly, it took me a while to reverse-engineer that strings in Windows are actually <code>uint16</code>, despite being declared <code>char</code>. But issues such as these are to be expected in a cross-language API.
</p>

<p>
In general, I did not find a good overview on how to interpret high-level C#-concepts in C. For example, it took a long time until I learned that objects in C# are reference counted, and that I would have to manage reference counts manually. Similarly, I had one rather thorny issue with memory allocations: in rare occasions (<code>PROPVARIANT</code>), C# is expected to re-allocate memory of an object if the object does not have enough memory when passed into a method. This does not work as intended if you don't use C#'s memory allocator to create the memory. <i>This</i> was really painful to figure out.
</p>

<p>
Another result of the API's cross-language heritage are its headers: There are <i>hundreds</i>. And they all contain both the C API and the C++ API, separated by the occasional <code>#ifdef __cplusplus</code> and <code>extern C</code>. Worse yet, pretty much every data type and declaration is wrapped in multiple levels of preprocessor macros and <code>typedef</code>. There are no doubt good reasons and a rich history for this, but it took me many hours to assemble all the necessary symbols from dozens of header files to even begin to call WASAPI functions.
</p>

<p>
Nevertheless, once these hurdles are overcome, the actual WASAPI API itself is well-structured and reasonably simple. You acquire an <code>IMMDeviceEnumerator</code>, which returns <code>IMMDeviceCollections</code> for microphones and speakers. These contain <code>IMMDevices</code>, which represent sound cards and their properties. You activate an <code>IMMDevice</code> with a desired data format to get an <code>IAudioClient</code>, which in turns produces an <code>IAudioRenderClient</code> or <code>IAudioCaptureClient</code> for playback or recording, respectively. Playback and recording themselves are done by requesting a buffer, and reading or writing raw data to that buffer. This is about as straight-forward as APIs get.
</p>

<p>
The documentation deserves even more praise: I have rarely seen such a well-documented API. There are high-level overview articles, there is commented example code, every object is described abstractly, and every method is described in detail and in reference to related methods and example code. There is no corner case that is left undescribed, and no error code without a detailed explanation. Truly, this is <i>exceptional</i> documentation that is a joy to work with!
</p>

<p>
In conclusion, WASAPI leaves me in a situation I am very unfamiliar with: praising Windows. There is a non-trivial impedance mismatch between C and C# that has to be overcome to <i>use</i> WASAPI from C. But once I understood this, the API itself and its documentation were easy to use and understand. Impressive!
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-audio.html">audio</a> <a href="https://bastibe.de/tag-programming.html">programming</a> <a href="https://bastibe.de/tag-windows.html">windows</a> ]]></description>
  <category><![CDATA[audio]]></category>
  <category><![CDATA[programming]]></category>
  <category><![CDATA[windows]]></category>
  <link>https://bastibe.de/2017-07-10-audio-apis-wasapi.html</link>
  <guid>https://bastibe.de/2017-07-10-audio-apis-wasapi.html</guid>
  <pubDate>Mon, 10 Jul 2017 14:12:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Audio APIs, Part 2: Pulseaudio / Linux]]></title>
  <description><![CDATA[
<p>
This is part two of a three-part series on the native audio APIs for Windows, Linux, and macOS. This second part is about PulseAudio on Linux.
</p>

<p>
It has long been a major frustration for my work that Python does not have a great package for playing and recording audio. My first step to improve this situation was a small contribution to <a href="https://people.csail.mit.edu/hubert/pyaudio/">PyAudio</a>, a CPython extension that exposes the C library <a href="http://www.portaudio.com/">PortAudio</a> to Python. However, I soon realized that PyAudio mirrors PortAudio a bit too closely for comfort. Thus, I set out to write <a href="https://github.com/bastibe/PySoundCard">PySoundCard</a>, which is a higher-level wrapper for PortAudio that tries to be more pythonic and uses NumPy arrays instead of untyped <code>bytes</code> buffers for audio data. However, I then realized that PortAudio itself had some inherent problems that a wrapper would not be able to solve, and a truly great solution would need to do it the hard way:
</p>

<p>
Instead of relying on PortAudio, I would have to use the native audio APIs of the three major platforms directly, and implement a simple, cross-platform, high-level, NumPy-aware Python API myself. This effort resulted in <a href="https://github.com/bastibe/Python-Audio">PythonAudio</a>, a new pure-Python package that uses <a href="http://cffi.readthedocs.io/en/latest/">CFFI</a> to talk to <a href="https://www.freedesktop.org/wiki/Software/PulseAudio/">PulseAudio</a> on Linux, <a href="https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html">Core Audio</a> on macOS, and <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd371455(v=vs.85).aspx">WASAPI</a>[1] on Windows.
</p>

<p>
This series of blog posts summarizes my experiences with these three APIs and outlines the basic structure of how to use them. For reference, the singular use case in PythonAudio is block-wise playing/recording of <code>float</code> data at arbitrary sampling rates and block sizes. All available sound cards should be listable and selectable, with correct detection of the system default sound cards (a feature that is very unreliable in PortAudio).
</p>

<p>
[1]: WASAPI is part of the Windows <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd370784(v=vs.85).aspx">Core Audio</a> APIs. To avoid confusion with the macOS API of the same name, I will always to refer to it as WASAPI.
</p>


<hr>

<div id="outline-container-org9d147b2" class="outline-2">
<h2 id="org9d147b2">PulseAudio</h2>
<div class="outline-text-2" id="text-org9d147b2">
<p>
PulseAudio is not the only audio API on Linux. There is the grandfather <a href="https://en.wikipedia.org/wiki/Open_Sound_System">OSS</a>, the more modern <a href="https://en.wikipedia.org/wiki/Advanced_Linux_Sound_Architecture">ALSA</a>, the more pro-focused <a href="https://en.wikipedia.org/wiki/JACK_Audio_Connection_Kit">JACK</a>, and the user-focused <a href="https://en.wikipedia.org/wiki/PulseAudio">PulseAudio</a>. Under the hood, PulseAudio uses ALSA for its actual audio input/output, but presents the user and applications with a much nicer API and UI.
</p>

<p>
The very nice thing about PulseAudio is that it is a native C API. It provides several levels of abstraction, the highest of which takes only a handful of lines of C to get audio playing. For the purposes of PythonAudio however, I had to look at the more in-depth <a href="https://freedesktop.org/software/pulseaudio/doxygen/async.html">asynchronous API</a>. Still, the API itself is relatively simple, and compactly defined in one simple header file.
</p>

<p>
It all starts with a <code>mainloop</code> and an associated <code>context</code>. While the <code>mainloop</code> is running, you can query the <code>context</code> for sources and sinks (aka microphones and speakers). The <code>context</code> can also create a <code>stream</code> that can be read or written (aka recorded or played). From a high level, this is all there is to it.
</p>

<p>
Most PulseAudio functions are asynchronous: Function calls return immediately, and call user-provided callback functions when they are ready to return results. While this may be a good structure for high-performance multithreaded C-code, it is somewhat cumbersome in Python. For PythonAudio, I wrapped this structure in regular Python functions that wait for the callback and return its data as normal return values.
</p>

<p>
Doing this shows just how old Python really is. Python is old-school in that it still thinks that concurrency is better solved with multiple, communicating processes, than with shared-memory threads. With such a mind set, there is a certain impedance mismatch to overcome when using PulseAudio. Every function call has to lock the main loop, and block while waiting for the callback to be called. After that, clean up by decrementing a reference count. This procedure is cumbersome, but not difficult.
</p>

<p>
What is difficult however, is the documentation. The API documentation is fine, as far as it goes. It could go into more detail with regards to edge cases and error conditions; But it truly lacks high-level overviews and examples. It took an unnecessarily long time to figure out the code path for audio playback and recording, simply because there is no document anywhere that details the sequence of events needed to get there. In the end, I followed some marginally-related example on the internet to get to that point, because the <i>two</i> examples provided by PulseAudio don't even use the asynchronous API.
</p>

<p>
Perhaps I am missing something, but it strikes me as strange that an API meant for audio recording and playback would not include an example that plays back and records audio.
</p>

<p>
On an application level, it can be problematic that PulseAudio seems to only value block sizes and latency requirements approximately. In particular, if computing resources become scarce, PulseAudio would rather increase latency/block sizes in the background than risk skipping. This might be convenient for a desktop application, but it is not ideal for signal processing, where latency can be crucial. It seems that I can work around these issues to an extent, but this is an inconvenience nontheless.
</p>

<p>
In general, I found PulseAudio reasonably easy to use, though. The documentation could use some work, and I don't particularly <i>like</i> the asynchronous programming style, but the API is simple and functional. Out of the three APIs of WASAPI/Windows, Core Audio/macOS, and PulseAudio/Linux, this one was probably the easiest to get working.
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-audio.html">audio</a> <a href="https://bastibe.de/tag-programming.html">programming</a> <a href="https://bastibe.de/tag-linux.html">linux</a> ]]></description>
  <category><![CDATA[audio]]></category>
  <category><![CDATA[programming]]></category>
  <category><![CDATA[linux]]></category>
  <link>https://bastibe.de/2017-06-27-audio-apis-pulseaudio.html</link>
  <guid>https://bastibe.de/2017-06-27-audio-apis-pulseaudio.html</guid>
  <pubDate>Tue, 27 Jun 2017 14:12:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Audio APIs, Part 1: Core Audio / macOS]]></title>
  <description><![CDATA[
<p>
This is part one of a three-part series on the native audio APIs for Windows, Linux, and macOS. This first part is about Core Audio on macOS.
</p>

<p>
It has long been a major frustration for my work that Python does not have a great package for playing and recording audio. My first step to improve this situation were a small contribution to <a href="https://people.csail.mit.edu/hubert/pyaudio/">PyAudio</a>, a CPython extension that exposes the C library <a href="http://www.portaudio.com/">PortAudio</a> to Python. However, I soon realized that PyAudio mirrors PortAudio a bit too closely for comfort. Thus, I set out to write <a href="https://github.com/bastibe/PySoundCard">PySoundCard</a>, which is a higher-level wrapper for PortAudio that tries to be more pythonic and uses NumPy arrays instead of untyped <code>bytes</code> buffers for audio data. However, I then realized that PortAudio itself had some inherent problems that a wrapper would not be able to solve, and a truly great solution would need to do it the hard way:
</p>

<p>
Instead of relying on PortAudio, I would have to use the native audio APIs of the three major platforms directly, and implement a simple, cross-platform, high-level, NumPy-aware Python API myself. This effort resulted in <a href="https://github.com/bastibe/Python-Audio">PythonAudio</a>, a new pure-Python package that uses <a href="http://cffi.readthedocs.io/en/latest/">CFFI</a> to talk to <a href="https://www.freedesktop.org/wiki/Software/PulseAudio/">PulseAudio</a> on Linux, <a href="https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html">Core Audio</a> on macOS, and <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd371455(v=vs.85).aspx">WASAPI</a>[1] on Windows.
</p>

<p>
This series of blog posts summarizes my experiences with these three APIs and outlines the basic structure of how to use them. For reference, the singular use case in PythonAudio is playing/recording of short blocks of <code>float</code> data at arbitrary sampling rates and block sizes. All connected sound cards should be listable and selectable, with correct detection of the system default sound card (a feature that is very unreliable in PortAudio).
</p>

<p>
[1]: WASAPI is part of the Windows <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd370784(v=vs.85).aspx">Core Audio</a> APIs. To avoid confusion with the macOS API of the same name, I will always to refer to it as WASAPI.
</p>


<hr>

<div id="outline-container-orgac5956a" class="outline-2">
<h2 id="orgac5956a">CoreAudio, or the Mac's best kept secret</h2>
<div class="outline-text-2" id="text-orgac5956a">
<p>
CoreAudio is the native audio library for macOS. It is known for its high performance, low latency, and horrible documentation. After having used the native audio APIs on all three platforms, CoreAudio was <i>by far</i> the hardest one to use. The main problem is lack of documentation and lack of feedback, and plain missing or broken features. Let's get started.
</p>

<p>
The basic unit of any CoreAudio program is the audio unit. An audio unit can be a source (aka microphone), a sink (aka speaker) or an audio processor (both sink and source). Each audio unit can have several input <i>buses</i>, and several output <i>buses</i>, each of which can have several <i>channels</i>. The meaning of these buses varies wildly and is often underdocumented. Furthermore, every audio unit has several <i>properties</i>, such as a sample rate, block sizes, and a data format, and <i>parameters</i>, which are like properties, but presumably different in some undocumented way.
</p>

<p>
In order to use an audio unit, you create an <code>AudioComponentDescription</code> that describes whether you want a source or sink unit, or an effect unit, and what kind of effect you want (AudioComponent is an alternative name for audio unit). With the description, you can create an <code>AudioComponentInstance</code>, which is then an opaque struct pointer to your newly created audio unit. So far so good.
</p>

<p>
The next step is then to configure the audio unit using <code>AudioUnitGetProperty</code> and <code>AudioUnitSetProperty</code>. This is surprisingly hard, since every property can be configured for every bus (sometimes called element) of every input or output of every unit, and the documentation is extremely terse on which of these combinations are valid. Some invalid combinations return error codes, while others only lead to errors during playback/recording. Furthermore, the definition of what constitutes an input or output is interpreted quite differently in different places: One place calls a microphone an <i>input</i>, since it records audio; another place will call it an <i>output</i>, since it outputs audio data to the system. In one crazy example, you have to configure a microphone unit by disabling its output bus 0, and enabling its input bus 1, but then read audio data from its ostensibly disabled output bus 0.
</p>

<p>
The property interface is untyped, meaning that every property has to be given an identifier, a void pointer that points to a matching data structure, and the size of that data structure. Sometimes the setter allocates additional memory, in which case the documentation does not contain any information on who should free this memory. Most objects are passed around as opaque struct pointers with dedicated constructor and destructor functions. All of this does not strike me as particularly C-like, even though CoreAudio is supposedly a native C library.
</p>

<p>
Once your audio unit is configured, you set a render callback function, and start the audio unit. All important interaction now happens within that callback function. In a strange reversal of typical control flow, input data to the callback function needs to be fetched by calling <code>AudioUnitRender</code> (evoked on the unit itself) from within the callback, while output is written to memory provided as callback function arguments. Many times during development, <code>AudioUnitRender</code> would return error codes because of an invalid property setting during initialization. Of course, it won't tell <i>which</i> property is actually at fault, just that it can't fulfill the render request at the moment.
</p>

<p>
Error codes in general are a difficult topic in CoreAudio. Most functions return an error code as an <code>OSStatus</code> value (aka <code>uint32</code>), and the header files usually contain a definition of some, but not all, possible error codes. Sometimes these error codes are descriptive and nice, but often they are way too general. My favorite is the frequent <code>kAudioUnitErr_CannotDoInCurrentContext</code>, which is just about as useless an error description as possible. Worse, some error codes are not defined as numeric constants, but as <code>int err = 'abcd'</code>, which makes them un-searchable in the source file. Luckily, this madness can be averted using <a href="https://osstatus.com/">https://osstatus.com/</a>, which is a dedicated database for <code>OSStatus</code> error codes.
</p>

<p>
By far the worst part of the CoreAudio API is that some properties are silently ignored. For example, you can set the sample rate or priming information on a microphone unit, and it will accept that property change and it will report that property as changed, but it will still use its default value when recording (aka "rendering" in CoreAudio). A speaker unit, in contrast, will honor the sample rate property, and resample as necessary. If you still need to resample your microphone recordings, you have to use a separate <code>AudioConverter</code> unit, which is its own bag of fun (and only documented in <a href="https://developer.apple.com/library/content/technotes/tn2091/_index.html#//apple_ref/doc/uid/DTS10003118-CH1-FORMATS">a remark</a> in one overview document).
</p>

<p>
Lastly, all the online documentation is written for Swift and Objective-C, while the implementation is C. Worse, the C headers contain vastly more information than the online documentation, and the online documentation often does not even reference the C header file name. Of course header files are spread into the CoreAudio framework, the AudioToolkit framework, and the AudioUnit framework, which makes even grepping a joy.
</p>

<p>
All of that said, once you know what to do and how to do it, the resulting code is relatively compact and readable. The API does contain inconsistencies and questionable design choices, but the real problem is the documentation. I spent way too much time reading the header files over and over again, and searching through (often outdated or misleading) <a href="https://developer.apple.com/library/content/samplecode/AVCaptureToAudioUnitOSX/Listings/CaptureSessionController_mm.html#//apple_ref/doc/uid/DTS40012879-CaptureSessionController_mm-DontLinkElementID_4">example projects</a> and <a href="https://developer.apple.com/library/content/technotes/tn2091/_index.html#//apple_ref/doc/uid/DTS10003118-CH1-FORMATS">vague</a> <a href="https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/AudioUnitDevelopmentFundamentals/AudioUnitDevelopmentFundamentals.html#//apple_ref/doc/uid/TP40003278-CH7-SW12">high-level</a> <a href="https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003278-CH1-SW2">overviews</a> for clues on how to interpret error messages and API documentation. I had somewhat better luck with a few <a href="http://kaniini.dereferenced.org/2014/08/31/CoreAudio-sucks.html">blog</a> <a href="http://subfurther.com/blog/2009/04/28/an-iphone-core-audio-brain-dump/">posts</a> on the subject, but the general consensus seems to be that the main concepts of CoreAudio are woefully under-explained, and documentation about edge cases is almost nonexistent. Needless to say, I did not enjoy my experience with CoreAudio.
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-audio.html">audio</a> <a href="https://bastibe.de/tag-programming.html">programming</a> <a href="https://bastibe.de/tag-macos.html">macos</a> ]]></description>
  <category><![CDATA[audio]]></category>
  <category><![CDATA[programming]]></category>
  <category><![CDATA[macos]]></category>
  <link>https://bastibe.de/2017-06-17-audio-apis-coreaudio.html</link>
  <guid>https://bastibe.de/2017-06-17-audio-apis-coreaudio.html</guid>
  <pubDate>Sat, 17 Jun 2017 14:45:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Scientific Code]]></title>
  <description><![CDATA[
<p>
A short while ago, I spent a few weeks collecting and evaluating various implementations of speech analysis algorithms for my current work. TL;DR: the general quality of scientific software is bad, and needs to improve.
</p>

<p>
Let me state up front that I am explicitly <i>not</i> talking about the quality of the science itself. This blog post is exclusively focused on the published <i>software</i>. In general, the problems were bad programming, old and unmaintained code, and lack of documentation. While none of these things mean <i>bad science</i>, they are a real challenge to reproducibility. Follow-up work can not quote algorithms they can't run.
</p>

<p>
Most scientists are not programmers, and use programming as a tool for doing science. Scientists typically don't conceptualize algorithms as code, and don't reason about their implementation in terms of code. Consequently, executable implementations tend to not read like code, either. And frankly, this is as it should be. In my area of research, programming abstractions are not a great medium for expressing scientific ideas, and programming transformations are weak in comparison to mathematical operations.
</p>

<p>
Still, the result is <i>bad code</i>. And <i>bad code is a problem for reproducibility and comparability</i>. Scientists therefore need to produce better code that is readable and portable. Straight-up letter-by-letter translations of the published math is just not enough, with all its single-letter variable names and complex nested expressions. We have to do better.
</p>

<p>
<b>Include an Example Script</b>
</p>

<p>
I have seen many instances of code that clearly worked at one point on the original author's machine, but doesn't on my computer. Maybe that is because I am running a different version of the programming environment, maybe my data is subtly different, maybe the author forgot to document a dependency. All of these happened to me, and all of these are exactly what you would expect from old, unmaintained code from non-expert programmers.
</p>

<p>
The least we can do to improve this situation, is to document how the code was supposed to work. A simple example script <i>with example data and example results</i> lets me verify that the code does what it is supposed to be doing. Without this, I can not diagnose errors. Worse, if no example results are included, I might conclude that the algorithm was bad, when in reality I was simply using an incorrect version of a dependency.
</p>

<p>
<b>Document Dependencies</b>
</p>

<p>
It is important to document all toolboxes, libraries, and programming languages used, <i>including their exact version and operating system</i>. At one point, I spent several hours debugging some Java code that worked in Java 5, but didn't on any recent Java version. If this had been documented, I could have fixed that error much more quickly. In another case, one piece of C code contained a subtle error if compiled with a 64 bit compiler. Again, this took a long time to track down, and would have been much easier if the original operating system and compiler version had been documented.
</p>

<p>
That same piece of C code could only be run by compiling several library dependency from old versions of their source code. In that case, the author helpfully included copies of the original source code for these libraries with his source distribution. Without that, I would never have gotten that piece of code to run!
</p>

<p>
Also, if at all possible, published code should use as few dependencies as possible. Not only might I not have access to that fancy Matlab Toolbox, but every step in the installation instructions is another thing that can go wrong. The more contained the code, the more likely it is that it will still be executable many years later.
</p>

<p>
<b>Higher Level Languages are better than Lower Level Languages</b>
</p>

<p>
In general, I had far less problems with non-compiled, high-level code for Matlab, Python, or R, than with low-level C or Java code. On the one hand, this is a technological problem: It is easier to keep an interpreter compatible with outdated code than it is to keep a more complex tool chains with compilers, linkers, and runtime libraries compatible. On the other hand though, this is a human problem as well: I happen to know Python, Matlab, and C pretty well, but I don't know much R or Java. Still, it is much easier to reason about the runtime behavior of R code (because I can inspect variables like in any other dynamic programming language) than to debug some unknown build tool interaction in Java (because compilation tool chains are typically much more complex and variable than REPLs).
</p>

<p>
<b>Keep it Simple</b>
</p>

<p>
A particular problem are compiled modules for an interpreted language. Such Mex files and CPython extensions are almost guaranteed to break when programming language versions change, and are often hard to upgrade, since the C APIs often change with the language version as well. Often, these compiled modules are provided for performance reasons. But what was painfully slow on the original author's work laptop a few years ago might not be a problem at all on a future compute cluster. If the code absolutely has to be provided a Mex file or a CPython extension, we should at least provide an interpreted version as well.
</p>

<p>
And speaking of compute clusters, I have had a lot of trouble with clever tricks such as massively parallelized code or GPU-optimized code. Not only does this age poorly, it also wreaks havoc when trying to run this code on a compute cluster. Such low-level performance optimizations are rarely a good idea for published scientific code, and should at least be optional and well-documented.
</p>

<p>
<b>Document the Code</b>
</p>

<p>
Code is never self-documenting. Given enough time, entropy increases inexorably, and times change. Conventions change, and what seemed obvious a few years ago might look like gibberish today. What is perfectly readable to a domain expert is inscrutable even to scientists of closely related areas of research. It is therefore necessary to always document published code, even if the code looks perfectly obvious to the author. In the same vein, we should refrain from using jargon in our code, and clearly declare our variables and invariants (they are bound to be different for different people).
</p>

<p>
Importantly, this includes documenting all file formats and data structures. Institutions often have in-house standards for how to represent certain kinds of data, and practitioners don't realize that these conventions are not followed universally. I had to ignore a few apparently high-quality algorithms simply because I could not figure out how to supply data to their code. For many other algorithms, I had to write custom data exporters and data importers. Again, an algorithm won't get quoted if it can't be run.
</p>

<p>
<b>Make it Automatable</b>
</p>

<p>
Another thing I see frequently are very fancy graphical user interfaces for scientific code. The only thing that breaks faster than compiled language extensions are GUI programs. GUIs are necessarily complex, and therefore hard to debug. And worse yet, if the code can only be run in a GUI, it can't be automated, and I won't be able to compare its performance in a big experiment with hundreds of runs. In effect, GUIs make an algorithm non-reproducible. If a GUI needs to be included in the code, it should at least be made optional.
</p>

<p>
<b>Do Release Code</b>
</p>

<p>
However, more importantly than anything I said so far: <i>Do</i> release source code for your algorithm. Nothing is more wasteful than reading about an amazing algorithm that I can't try out. If no source code is released, it is not reproducible, it can't be compared to other algorithms in the field, and it might as well not have been published.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <link>https://bastibe.de/2017-05-14-scientific-code.html</link>
  <guid>https://bastibe.de/2017-05-14-scientific-code.html</guid>
  <pubDate>Sun, 14 May 2017 13:05:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Matlab Metaprogramming]]></title>
  <description><![CDATA[
<p>
Why is it, that I find Matlab to be a fine teaching tool and a fine tool for solving engineering problems, but at the same time, extremely cumbersome for my own work? Recently, the answer struck me: <i>metaprogramming in Matlab sucks</i>.
</p>

<p>
Matlab is marketed as a tool for engineers to solve engineering problems. There are convenient data structures for numerical data (arrays, tables), less convenient data structures for non-numeric data (cells, structs, chars), and a host of expensive but powerful functions and methods for working with this kind of data. This is the happy path.
</p>

<p>
But don't stray too far from the happy path; horrors lurk where The Mathworks don't dare going. Basic stuff like talking to sockets or interacting with other programs is very cumbersome in Matlab, and sometimes even downright impossible for the lack of threads, pipes, and similar infrastructure. But this is common knowledge, and consistent with Matlab's goals as an engineering tool, not a general purpose programming language. These are first-order problems, and they are rarely insurmountable.
</p>

<p>
The more insidious problem is metaprogramming, i.e. when the objects of your code are code objects themselves. The first order use of programming is to solve real-world problems. If these problems are numeric in nature, Matlab has got you covered. But as every programmer discovers at some point, the second order use of programming is to solve programming problems. And by golly, will Matlab let you down when you try that!
</p>

<p>
As soon as you climb that ladder of abstraction, and the objects of your code become code objects themselves, you will enter weird country. You think <code>exist</code> will tell you whether a variable name is taken? Try calling it on a method. You think <code>nargout</code> will always give you a number? Again, methods will enlighten you. Quick, how do you capture all output arguments of a function call in a variable? <code>x = cell(nargout(fun), 1); [x{:}] = fun(...)</code>, obviously (this sometimes fails). And don't even think of trying to overload <code>subsref</code> to create something generic. Those <code>subsref</code> semantics are <a href="https://mathworks.com/help/matlab/matlab_oop/code-patterns-for-subsref-and-subsasgn-methods.html">crazy talk</a>!
</p>

<p>
I could go on. The real power of code is abstraction. We use programming to repeatedly and reliably solve similar problems. The logical next step is to use those same programming tools to solve similar <i>kinds</i> of problems. This happens to all of us, and Matlab makes it extremely hard to deal with. Thus, it puts a ceiling on the level of abstraction that is reasonably achievable, and limits engineers to first-order solutions. And after a few years of acclimatization, it will put that same ceiling on those engineers' thinking, because you can't reason about what you can't express.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-matlab.html">matlab</a> ]]></description>
  <category><![CDATA[matlab]]></category>
  <link>https://bastibe.de/2017-04-12-matlab-metaprogramming.html</link>
  <guid>https://bastibe.de/2017-04-12-matlab-metaprogramming.html</guid>
  <pubDate>Wed, 12 Apr 2017 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Pip is great]]></title>
  <description><![CDATA[
<p>
<a href="http://bastibe.de/2011-02-03-installing-python-slash-numpy-slash-scipy-slash-matplotlib-on-osx.html">Installing</a> <a href="http://bastibe.de/2011-03-04-installing-pygame-using-homebrew.html">Python</a> <a href="http://bastibe.de/2011-08-01-compiling-scipy-and-matplotlib-using-pip-on-lion.html">packages</a> <a href="http://bastibe.de/2011-10-13-compiling-scipy-and-matplotlib-again.html">used</a> to be a pain. Very surprisingly, this is no longer the case. Nowadays, <code>pip install whatever</code> will reliably install pretty much anything without any trouble.
</p>

<p>
To recap, the problem is that many Python packages rely on C code, which needs to be compiled before installation. In the past, this burden was mostly on the user. Depending on the user's knowledge of C and compilers, and the user's operating system, this could become almost arbitrarily hairy.
</p>

<p>
This problem was solved, to some extent, using pre-compiled packages, first as <a href="http://www.lfd.uci.edu/~gohlke/pythonlibs/">binary installers</a> on the package websites, then pre-packaged <a href="http://winpython.github.io/">Python</a> <a href="https://www.continuum.io/anaconda-overview">distributions</a>, and later through third-party package managers such as <a href="http://conda.pydata.org/docs/">conda</a>.
</p>

<p>
This worked well, but it fractured the ecosystem into several different mostly-compatible package sources. This was no big problem, but users had to decide on a package-by-package basis whether to download an installer, use conda, or use pip.
</p>

<p>
But I am happy to announce that these dark days are behind us now. Pip now automatically installs binary Python packages called <a href="http://wheel.readthedocs.io/en/latest/">wheels</a>, and most package developers <a href="http://pythonwheels.com/">do now provide</a> wheels on <a href="https://pypi.python.org/pypi">PyPI</a>. This is so obviously superior to the past that many high-profile packages don't even provide binary installers any more.
</p>

<p>
For me, this means I don't have to rely on conda any longer. I don't have to keep a mental list of which packages to install though conda and which packages to install through pip any longer. I can go back to using virtualenv instead of conda-envs<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup> again. I don't have to tell students to download pre-packaged Python distributions any longer. Pip is great!
</p>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
Not because I dislike conda, just to simplify my development environment.
</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-python.html">python</a> ]]></description>
  <category><![CDATA[python]]></category>
  <link>https://bastibe.de/2016-11-24-pip-is-great.html</link>
  <guid>https://bastibe.de/2016-11-24-pip-is-great.html</guid>
  <pubDate>Thu, 24 Nov 2016 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Soma]]></title>
  <description><![CDATA[
<p>
For a long time, I was afraid of picking up Soma, since it came from the developers who did Amnesia. Amnesia was the first game that scared me so thoroughly that I just couldn't bring myself to pick it up again after the first session. I admired it for its amazing world design, interactivity, and story, but it was too scary for me. I don't enjoy being scared.
</p>

<p>
I was thus of two minds when I heard about Soma: Soma was supposed to be less scary, and SciFi. But still, let me get this out of the way; This game scared me whitless. I had to use an online game guide to warn me of monsters and tell me how to evade them. I was too scared to figure this stuff out by myself, all alone in this creepy, nasty, underwater space station.
</p>

<p>
But at the same time, this game delivered one of the best stories I have ever seen in a video game. The story left me shaken and thoughtful for days, and the story was what dragged me back into the game even though I was really struggling with the monster sections. Even the delivery through conversations, environmental clues, and audio logs, was truly outstanding. I just love grimy Alien-style SciFi, and this is one of the very few video game stories that could fill more than a paragraph or two in a well-written book. I love it.
</p>

<p>
Apparently, if you like horror games, this is a very mild one. Boring even, if you can believe my favorite <a href="https://www.youtube.com/watch?v=Y6BPcSYibco">online</a> <a href="https://www.youtube.com/watch?v=J4tbbcWqDyY">critics</a>. But believe me, it was right on the edge of what I was able to take. I still can't quite decide whether I would have preferred this game without the monsters, or whether the monsters were a necessary tool for evoking this intense sense of dread on the lonely SciFi ocean floor. Maybe the monsters lent some much-needed life and interactivity to the walk-em-up formula.
</p>

<p>
At any rate, I thoroughly enjoyed this experience, and can't wait for what this developer will create next. I wholeheartedly recommend this, as one of the best SciFi stories of this year, in any medium. ★★★★★
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-games.html">games</a> ]]></description>
  <category><![CDATA[games]]></category>
  <link>https://bastibe.de/2016-11-22-soma.html</link>
  <guid>https://bastibe.de/2016-11-22-soma.html</guid>
  <pubDate>Tue, 22 Nov 2016 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[MATLAB Syntax]]></title>
  <description><![CDATA[
<p>
In a <a href="https://github.com/bastibe/MatlabCodeAnalyzer">recent project</a>, I tried to parse MATLAB code. During this trying exercise, I stumbled upon a few&#x2026; <i>unique</i> design decisions of the MATLAB language:
</p>

<div id="outline-container-orge7fb030" class="outline-2">
<h2 id="orge7fb030">Use of apostrophes (<code>'</code>)</h2>
<div class="outline-text-2" id="text-orge7fb030">
<p>
Apostrophes can mean one of two things: If applied as a unary postfix operator, it means <i>transpose</i>. If used as a unary prefix operator, it marks the start of a string. While not a big problem for human readers, this makes code surprisingly hard to parse. The interesting bit about this, though, is the fact that there would have been a much easier way to do this: Why not use double quotation marks for strings, and apostrophes for transpose? The double quotation mark is <i>never</i> used in MATLAB, so this would have been a very easy choice.
</p>
</div>
</div>

<div id="outline-container-org9aac744" class="outline-2">
<h2 id="org9aac744">Use of parens (<code>()</code>)</h2>
<div class="outline-text-2" id="text-org9aac744">
<p>
If Parens follow a variable name, they can mean one of two things: If the variable is a function, the parens denote a <i>function call</i>. If the variable is anything else, this is an indexing operation. This can actually be very confusing to readers, since it makes it entirely unclear what kind of operation <code>foo(5)</code> will execute without knowledge about <code>foo</code> (which might not be available until runtime). Again, this could have been easily solved by using brackets (<code>[]</code>) for indexing, and parens (<code>()</code>) for function calls.
</p>
</div>
</div>

<div id="outline-container-org6173934" class="outline-2">
<h2 id="org6173934">Use of braces (<code>{}</code>) and cell arrays</h2>
<div class="outline-text-2" id="text-org6173934">
<p>
Cell arrays are multi-dimensional, ordered, heterogeneous collections of things. But in contrast to every other collection (structs, objects, maps, tables, matrices), they are not indexed using parens, but <i>braces</i>. Why? I don't know. In fact, you <i>can</i> index cell arrays using parens, but this only yields a new cell array with only one value. Why would this ever be useful? I have no explanation. This constantly leads to errors, and for the life of me I can not think of a reason for this behavior.
</p>
</div>
</div>

<div id="outline-container-org1a8b884" class="outline-2">
<h2 id="org1a8b884">Use of line breaks</h2>
<div class="outline-text-2" id="text-org1a8b884">
<p>
In MATLAB, your line can end on one of three characters: A newline character, a semicolon (<code>;</code>), and a comma (,). As we all know, the semicolon suppresses program output, while the newline character does not. The comma ends the logical line, but does not suppress program output. This is a relatively little-known feature, so I thought it would be useful to share it. Except, the meaning of <code>;</code> and , changes in literals (like <code>[1, 2; 3, 4]</code> or <code>{'a', 'b'; 3, 4}</code>). Here, commas separate values on the same row and are optional, and semicolons end the current row. Interestingly, literals also change the meaning of the newline character: Inside a literal, a newline acts just like a semicolon, overrides a preceding comma, and you don't have to use ellipsis (<code>...</code>) for line continuations.
</p>
</div>
</div>

<div id="outline-container-org1abcec1" class="outline-2">
<h2 id="org1abcec1">Syntax rules for commands</h2>
<div class="outline-text-2" id="text-org1abcec1">
<p>
Commands are function calls without the parenthesis, like <code>help disp</code>, which is syntactically equivalent to <code>help('disp')</code>. You see, if you just specify a function name (can't be a compound expression or a function handle), and don't use parenthesis, all following words will be interpreted as strings, and passed to the function. This is actually kind of a neat feature. However, how do you differentiate between <code>variable_name + 5</code> and <code>help + 5</code>? The answer is: Commands are actually a bit more complex. A command starts with a function name, followed by a space, which is not followed by an operator <i>and a space</i>. Thus, <code>help +5 + 4</code> is a command, while <code>help + 5 + 4</code> is an addition. Tricky!
</p>
</div>
</div>

<div id="outline-container-org9fd8692" class="outline-2">
<h2 id="org9fd8692">The more-than-one-value value</h2>
<div class="outline-text-2" id="text-org9fd8692">
<p>
If you want to save more than one value in a variable, you can use a collection (structs, matrices, maps, tables, cell arrays). In addition though, MATLAB knows another way of handling more than one values at once: The thing you get when you index a cell array with <code>{:}</code> or assign a function call with more than one result. In that case, you get something that is assignable to several variables, but that is not itself a collection. Just another quirk of MATLAB's indexing logic. However, you can capture these values into matrices or cell arrays using brackets or braces, like this: <code>{x{:}}</code> or <code>[x{:}]</code>. Note that this also works in assignments in a confusing way: <code>[z{:}] = x{:}</code> (if both x and z have the same length). Incidentally, this is often a neat way of converting between different kinds of collections (but utterly unreadable, because type information is hopelessly lost).
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-matlab.html">matlab</a> ]]></description>
  <category><![CDATA[matlab]]></category>
  <link>https://bastibe.de/2016-09-07-matlab-syntax.html</link>
  <guid>https://bastibe.de/2016-09-07-matlab-syntax.html</guid>
  <pubDate>Wed, 07 Sep 2016 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[P⋅O⋅L⋅L⋅E⋅N and Walk 'em ups]]></title>
  <description><![CDATA[
<p>
I like boring games. I like games that give me time to think. Like <a href="http://x-plane.org/">flight</a> <a href="http://www.prepar3d.com/">simulators</a>, <a href="http://eurotrucksimulator2.com/">truck</a> <a href="http://www.americantrucksimulator.com/">simulators</a>, <a href="https://en.wikipedia.org/wiki/Civilization_V">history simulators</a>, and (don't call them walking simulators) <a href="https://en.wikipedia.org/wiki/The_Stanley_Parable">walk</a> '<a href="http://gonehome.game/">em</a> <a href="http://www.firewatchgame.com/">ups</a>. And this weekend, this year's Steam Summer Sale started, and thus it was time to get some gaming done!
</p>

<p>
First, I played <a href="https://en.wikipedia.org/wiki/Everybody%27s_Gone_to_the_Rapture">Everybody's Gone to the Rapture</a>, a walk 'em up that got good reviews, and was especially praised for it's story. And it dutifully enraptured me, with its British landscapes, and personal story lines. But somehow it didn't quite connect. Maybe I'm not <a href="http://www.gamesradar.com/how-enjoy-everybodys-gone-rapture-real-englishman-explains/">British</a> enough, and I certainly didn't get all of the story. Still, this is well worth picking up, and visiting a digital Shropshire after just having visited the real one earlier this year was a real treat!
</p>

<p>
Second, I played P⋅O⋅L⋅L⋅E⋅N. It did not start well: The download took ages, I had to unplug all that fancy flight simulation gear to get it to recognize my controller, and performance was rather lackluster. Oh, and reviews were rather mediocre, too. (Also, here's a free tip for you if you games developers: putting fancy Unicode characters into your game title does not improve SEO).
</p>

<p>
But, I entirely fell in love with P⋅O⋅L⋅L⋅E⋅N! You arrive on <a href="https://en.wikipedia.org/wiki/Titan_(moon)">Titan</a> in your dinky near-future space capsule, take a short walk on the surface of the moon, and then explore the local space station. Of course, something went wrong, and the space station is deserted. Oh, and there is something about space bees.
</p>

<p>
What really worked for me here was the environmental story telling. This is a space station much in the tradition of <a href="https://typesetinthefuture.com/2014/01/31/2001-a-space-odyssey/">2001: A Space Odyssey</a> and <a href="https://typesetinthefuture.com/2014/12/01/alien/">Alien</a>. It's that perfect utilitarian and inhumanely sterile work place that human corporation always strive for, and human employees always mess up. The stark industrial bleakness of these <a href="http://scificorridorarchive.com/">space corridors</a> is the perfect backdrop to make those little human irregularities really stand out.
</p>

<p>
There is no conflict, only light puzzles, and the story is developed only through voice diaries and environmental clutter. But in contrast to Rapture, it all makes sense. The futurist setting, the deep humanity of the people dealing with it. The creepiness of machines without operators. The struggle of the scientists and engineers against the forces of nature and greedy corporations. The nods —nay— genuflections to everything that has ever been great in Scifi. Even that Kubrick ending. I loved every inch of this! ★★★★★
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-games.html">games</a> ]]></description>
  <category><![CDATA[games]]></category>
  <link>https://bastibe.de/2016-06-26-pollen.html</link>
  <guid>https://bastibe.de/2016-06-26-pollen.html</guid>
  <pubDate>Sun, 26 Jun 2016 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Transplant, revisited]]></title>
  <description><![CDATA[
<p>
A few months ago, I <a href="http://bastibe.de/2015-11-03-matlab-engine-performance.html">talked about</a> the performance of calling Matlab from Python. Since then, I implemented a few optimizations that make working with Transplant a lot faster:
</p>


<figure id="org7fba5e7">
<img src="http://bastibe.de/static/2016-06/timings.png" alt="timings.png">

</figure>

<p>
The workload consisted of generating a bunch of random numbers (not included in the times), and sending them to Matlab for computation. This task is entirely dominated by the time it takes to transfer the data to Matlab (see table at the end for intra-language benchmarks of the same task).
</p>

<p>
As you can see, the new Transplant is significantly faster <del>for small workloads, and still a factor of two faster for larger amounts of data</del>. It is now almost always a faster solution than the Matlab Engine for Python (MEfP) and Oct2Py. <del>For very large datasets, Oct2Py might be preferable, though.</del>
</p>

<p>
This improvement comes from three major changes: Matlab functions are now returned as callable objects instead of ad-hoc functions, Transplant now uses MsgPack instead of JSON, and <code>loadlibrary</code> instead of a Mex file to call into <code>libzmq</code>. All of these changes are entirely under the hood, though, and the public API remains unchanged.
</p>

<p>
The callable object thing is the big one for small workloads. The advantage is that the objects will only fetch documentation if <code>__doc__</code> is actually asked for. As it turns out, running <code>help('funcname')</code> for every function call is kind of a big overhead.
</p>

<p>
Bigger workloads however are dominated by the time it takes Matlab to decode the data. String parsing is very slow in Matlab, which is a bad thing indeed if you're planning to read a couple hundred megabytes of JSON. Thus, I replaced JSON with MsgPack, which eliminates the parsing overhead almost entirely. JSON messaging is still available, though, if you pass <code>msgformat='json'</code> to the constructor. <b>Edit:</b> Additionally, binary data is no longer encoded as base64 strings, but passed directly through MsgPack. This yields about a ten-fold performance improvement, especially for larger data sets.
</p>

<p>
Lastly, I rewrote the ZeroMQ interaction to use <code>loadlibrary</code> instead of a Mex file. This has no impact on processing speed at all, but you don't have to <a href="http://bastibe.de/2016-05-31-Matlab-FFI.html">worry about</a> compiling that C code any more.
</p>

<p>
Oh, and Transplant now works on Windows!
</p>

<p>
Here is the above data again in tabular form:
</p>

<table>


<colgroup>
<col  class="org-left">

<col  class="org-left">

<col  class="org-left">

<col  class="org-left">

<col  class="org-left">

<col  class="org-left">

<col  class="org-left">

<col  class="org-left">
</colgroup>
<thead>
<tr>
<th scope="col" class="org-left">Task</th>
<th scope="col" class="org-left">New Transplant</th>
<th scope="col" class="org-left">Old Transplant</th>
<th scope="col" class="org-left">Oct2Py</th>
<th scope="col" class="org-left">MEfP</th>
<th scope="col" class="org-left">Matlab</th>
<th scope="col" class="org-left">Numpy</th>
<th scope="col" class="org-left">Octave</th>
</tr>
</thead>
<tbody>
<tr>
<td class="org-left">startup</td>
<td class="org-left">4.8 s</td>
<td class="org-left">5.8 s</td>
<td class="org-left">11 ms</td>
<td class="org-left">4.6 s</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
<td class="org-left">&#xa0;</td>
</tr>

<tr>
<td class="org-left">sum(randn(1,1))</td>
<td class="org-left">3.36 ms</td>
<td class="org-left">34.2 ms</td>
<td class="org-left">29.6 ms</td>
<td class="org-left">1.8 ms</td>
<td class="org-left">9.6 μs</td>
<td class="org-left">1.8 μs</td>
<td class="org-left">6 μs</td>
</tr>

<tr>
<td class="org-left">sum(randn(1,10))</td>
<td class="org-left">3.71 ms</td>
<td class="org-left">35.8 ms</td>
<td class="org-left">30.5 ms</td>
<td class="org-left">1.8 ms</td>
<td class="org-left">1.8 μs</td>
<td class="org-left">1.8 μs</td>
<td class="org-left">9 μs</td>
</tr>

<tr>
<td class="org-left">sum(randn(1,100))</td>
<td class="org-left">3.27 ms</td>
<td class="org-left">33.9 ms</td>
<td class="org-left">29.5 ms</td>
<td class="org-left">2.06 ms</td>
<td class="org-left">2.2 μs</td>
<td class="org-left">1.8 μs</td>
<td class="org-left">9 μs</td>
</tr>

<tr>
<td class="org-left">sum(randn(1,1000))</td>
<td class="org-left">4.26 ms</td>
<td class="org-left">32.7 ms</td>
<td class="org-left">30.6 ms</td>
<td class="org-left">9.1 ms</td>
<td class="org-left">4.1 μs</td>
<td class="org-left">2.3 μs</td>
<td class="org-left">12 μs</td>
</tr>

<tr>
<td class="org-left">sum(randn(1,1e4))</td>
<td class="org-left">4.35 ms</td>
<td class="org-left">34.5 ms</td>
<td class="org-left">30 ms</td>
<td class="org-left">72.2 ms</td>
<td class="org-left">25 μs</td>
<td class="org-left">5.8 μs</td>
<td class="org-left">38 μs</td>
</tr>

<tr>
<td class="org-left">sum(randn(1,1e5))</td>
<td class="org-left">5.45 ms</td>
<td class="org-left">86.1 ms</td>
<td class="org-left">31.2 ms</td>
<td class="org-left">712 ms</td>
<td class="org-left">55 μs</td>
<td class="org-left">38.6 μs</td>
<td class="org-left">280 μs</td>
</tr>

<tr>
<td class="org-left">sum(randn(1,1e6))</td>
<td class="org-left">44.1 ms</td>
<td class="org-left">874 ms</td>
<td class="org-left">45.7 ms</td>
<td class="org-left">7.21 s</td>
<td class="org-left">430 μs</td>
<td class="org-left">355 μs</td>
<td class="org-left">2.2 ms</td>
</tr>

<tr>
<td class="org-left">sum(randn(1,1e7))</td>
<td class="org-left">285 ms</td>
<td class="org-left">10.6 s</td>
<td class="org-left">643 ms</td>
<td class="org-left">72 s</td>
<td class="org-left">3.5 ms</td>
<td class="org-left">5.04 ms</td>
<td class="org-left">22 ms</td>
</tr>
</tbody>
</table>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-matlab.html">matlab</a> <a href="https://bastibe.de/tag-python.html">python</a> ]]></description>
  <category><![CDATA[matlab]]></category>
  <category><![CDATA[python]]></category>
  <link>https://bastibe.de/2016-06-21-transplant-revisited.html</link>
  <guid>https://bastibe.de/2016-06-21-transplant-revisited.html</guid>
  <pubDate>Tue, 21 Jun 2016 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Teaching with Matlab Live Scripts]]></title>
  <description><![CDATA[
<p>
For a few years now, I have been teaching programming courses using <i>notebooks</i>. A notebook is an interactive document that can contain code, results, graphs, math, and prose. It is the perfect teaching tool:
</p>

<p>
You can combine introductory resources with application examples, assignments, and results. And after the lecture, students can refer to these notebooks at their leisure, and re-run example code, or try different approaches with known data.
</p>

<p>
The first time I saw this was with the <a href="http://jupyter.org/">Jupyter notebook</a> (née IPython notebook). I immediately used it for teaching an introductory programming course in Python.
</p>

<p>
Later, I took over a Matlab course, but Matlab lacked a notebook. So for the next two years of teaching Matlab, I hacked up a small IPython extension that allowed me to run Matlab code in an Jupyter notebook as a cell magic.
</p>

<p>
Now, with 2016a, Matlab introduced <a href="http://de.mathworks.com/help/releases/R2016a/matlab/live-scripts.html">Live Scripts</a>, which is Mathworkian for notebook. This blog post is about how Live Scripts compare to Jupyter notebooks.
</p>

<p>
First off, Live Scripts <i>work</i>. The basic functionality is there: Code, prose, figures, and math can be saved in one document; The notebook can be exported as PDF and HTML, and Students can download the notebook and play with it. This latter part was not possible with my homegrown solution earlier.
</p>

<p>
However, Live Scripts are new, and still contain a number of bugs. You can't customize figure sizes, formatting options are very basic, image rendering is terrible, and math rendering using LaTeX is of poor quality and limited. Also, using Live Scripts on a retina Mac is borderline impossible: Matlab crashes on screen resolution changes (i.e. connecting a projector), Live Scripts render REALLY slowly (type a word, watch the characters crawl onto the screen one by one), and all figures export in twice their intended size (fixed in 2016b). You can work around some of these issues by starting Matlab in <a href="https://support.apple.com/en-us/HT202471">Low Resolution Mode</a>.
</p>

<p>
No doubt some of these issues are going to get addressed in future releases. 2016b added script-local functions, which I read mostly as "you can now write functions in Live Scripts", and autocorrection-like text replacements that convert Markdown formatting into formatted text. This is highly appreciated.
</p>

<p>
Additionally though, here are a few features I would love to see:
</p>

<ul class="org-ul">
<li>Nested lists, and lists entries that contain newlines (i.e. differentiate between line breaks and paragraph breaks).</li>
<li>Indented text, for quoting things, or to work around the lack of multi-line list entries.</li>
<li>More headline levels.</li>
<li>Magics. This is probably a long shot, but line/cell magics in Jupyter notebooks are really useful.</li>
</ul>

<p>
Still, all griping aside, I want to reiterate that Live Scripts <i>work</i>. They aren't quite as nice as Jupyter notebooks, but they serve their purpose, and are a tremendously useful teaching tool.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-matlab.html">matlab</a> ]]></description>
  <category><![CDATA[matlab]]></category>
  <link>https://bastibe.de/2016-06-15-matlab-live-scripts.html</link>
  <guid>https://bastibe.de/2016-06-15-matlab-live-scripts.html</guid>
  <pubDate>Wed, 15 Jun 2016 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Matlab has an FFI and it is not Mex]]></title>
  <description><![CDATA[
<p>
Sometimes, you just have to use C code. There's no way around it. C is the lingua franca and bedrock of our computational world. Even in Matlab, sometimes, you just have to call into a C library.
</p>

<p>
So, you grab your towel, you bite the bullet, you strap into your K&amp;R, and get down to it: You start writing a Mex file. And you curse, and you cry, because writing C is hard, and Mex doesn't exactly make it any better. But you know what? <i>There is a better way!</i>
</p>

<p>
Because, unbeknownst to many, Matlab includes a Foreign Function Interface. The technique was probably pioneered by <a href="https://common-lisp.net/project/cffi/">Common Lisp</a>, and has since <a href="http://luajit.org/ext_ffi.html">been</a> <a href="http://cffi.readthedocs.io/en/latest/overview.html">widely</a> <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html">adopted</a> <a href="https://en.wikipedia.org/wiki/Foreign_function_interface">everywhere</a>: calling functions in a C library without writing any C code and without invoking a compiler!
</p>

<p>
Mind you, there remains a large and essential impedance mismatch between C's statically typed calling conventions and the vagaries of a dynamically typed language such as Matlab, and even the nicest FFI can't completely hide that fact. But anything is better than the abomination that is Mex.
</p>

<p>
So here goes, a very simple C library that adds two arrays:
</p>

<div class="org-src-container">
<pre class="src src-C">// test.c:
#include test.h

void add_arrays(float *out, float* in, size_t length) {
    for (size_t n=0; n&lt;length; n++) {
        out[n] += in[n];
    }
}

// test.h:
#include &lt;stddef.h&gt;
void add_arrays(float *out, float *in, size_t length);
</pre>
</div>

<p>
Let's compile it! <code>gcc -shared -std=c99 -o test.so test.c</code> will do the trick.
</p>

<p>
Now, let's load that library into Matlab with <code>loadlibrary</code>:
</p>

<div class="org-src-container">
<pre class="src src-octave">if not(libisloaded('test'))
    [notfound, warnings] = loadlibrary('test.so', 'test.h');
    assert(isempty(notfound), 'could not load test library')
end
</pre>
</div>

<p>
Note that <code>loadlibrary</code> can't parse many things you would commonly find in header files, so you will likely have to strip them down to the bare essentials. Additionally, <code>loadlibrary</code> doesn't throw errors if it can't load a library, so we always have to check the <code>notfound</code> output argument to see if the library was actually loaded successfully.
</p>

<p>
With that, we can call functions in that library using <code>calllib</code>. But we can't just pass in Matlab vectors, that would be too easy. We first have to convert them to something C can understand: Pointers
</p>

<div class="org-src-container">
<pre class="src src-octave">vector1 = [1 2 3 4 5];
vector2 = [9 8 7 6 5];

vector1ptr = libpointer('singlePointer', vector1);
vector2ptr = libpointer('singlePointer', vector2);
</pre>
</div>

<p>
What is nice about this is that this automatically converts the vectors from <code>double</code> to <code>float</code>. What is less nice is that it uses its weird <code>singlePtr</code> notation instead of the more canonical <code>float*</code> that you would expect from a self-respecting C header.
</p>

<p>
Then, finally, let's call our function:
</p>

<div class="org-src-container">
<pre class="src src-octave">calllib('test', 'add_arrays', vector1ptr, vector2ptr, length(vector1));
</pre>
</div>

<p>
If you see no errors, everything went smoothly, and you will now have changed the content of vector1ptr, which we can have a look at like this:
</p>

<div class="org-src-container">
<pre class="src src-octave">added_vectors = vector1ptr.Value;
</pre>
</div>

<p>
Note that this didn't change the contents of <code>vector1</code>, only of the newly created pointer. So there will always be some memory overhead to this technique in comparison to Mex files. However, runtime overhead seems pretty fine:
</p>

<div class="org-src-container">
<pre class="src src-octave">timeit(@() calllib('test', 'add_arrays', vector1ptr, vector2ptr, length(vector1)))
%   ans = 1.9155e-05
timeit(@() the_same_thing_but_as_a_mex_file(single(vector1), single(vector2)))
%   ans = 4.6262e-05
timeit(@() the_same_thing_plus_argument_conversion(vector1, vector2))
%   ans = 1.2326e-04
</pre>
</div>

<p>
So as you can see, the <code>calllib</code> is plenty fast. However, if you add the Matlab code for converting the double arrays to pointers and extracting the summed data afterwards, the FFI is noticeably slower than a Mex file.
</p>

<p>
However, If I ask myself whether I would sacrifice 0.00007 seconds of computational overhead for hours of my life <i>not</i> spent with Mex, there really is no competition. I will choose Matlab's FFI over writing Mex files every time.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-matlab.html">matlab</a> ]]></description>
  <category><![CDATA[matlab]]></category>
  <link>https://bastibe.de/2016-05-31-Matlab-FFI.html</link>
  <guid>https://bastibe.de/2016-05-31-Matlab-FFI.html</guid>
  <pubDate>Tue, 31 May 2016 11:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Updating the Matplotlib Font Cache]]></title>
  <description><![CDATA[
<p>
When publishing papers or articles, I want my plots to integrate with the text surrounding them. I want them to use the correct font size, and the correct font.
</p>

<p>
This is easy to do with Matplotlib:
</p>

<div class="org-src-container">
<pre class="src src-python">import matplotlib
matplotlib.rcParams['font.size'] = 12
matplotlib.rcParams['font.family'] = 'Calibri'
</pre>
</div>

<p>
However, sometimes, Matplotlib won't find the correct, even though it is clearly installed. This happens when Matplotlib's internal font cache is out of date.
</p>

<p>
To refresh the font cache, use
</p>

<div class="org-src-container">
<pre class="src src-python">matplotlib.font_manager._rebuild()
</pre>
</div>

<p>
Happy Plotting!
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-python.html">python</a> ]]></description>
  <category><![CDATA[python]]></category>
  <link>https://bastibe.de/2016-05-30-matplotlib-font-cache.html</link>
  <guid>https://bastibe.de/2016-05-30-matplotlib-font-cache.html</guid>
  <pubDate>Mon, 30 May 2016 16:30:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[The Style of Scientific Code]]></title>
  <description><![CDATA[
<p>
What does quality code look like? One common school of thought focuses on small, descriptive functions that take few arguments. To quote from <a href="https://en.wikipedia.org/wiki/Robert_Cecil_Martin">Clean Code</a>: "The first rule of functions is that they should be small", on the order of less than ten lines. "Functions should not be large enough to hold nested structures". "The ideal number of arguments for a function is zero [, one, or two]. Three [or more] arguments should be avoided where possible".
</p>

<p>
A few years ago, when I was working mostly on user interaction and data management, all of this made sense to me. What is the overhead of a few function calls and class lookups here and there if it makes the code more readable? In other words: Readability counts, and is usually more important than performance.
</p>

<p>
But lately, I have come to struggle with these rules. I am now writing a lot of scientific code, where algorithms are intrinsically complex beyond the syntactic complexity of the code. How do you "Express yourself in code [instead of comments]", when that code only consists of linear algebra and matrix multiplications?
</p>

<div class="org-src-container">
<pre class="src src-python">def rectwin_spectrum(angular_frequency, specsize):
    """The spectrum of a rectangular window. [...]"""
    # In case of angular_frequency == 0, this will calculate NaN. Since
    # this will be corrected later, suppress the warning.
    with np.errstate(invalid='ignore'):
        spectrum = ( np.exp(-1j*angular_frequency*(specsize-1)/2) *
                     np.sin(specsize*angular_frequency/2) /
                     np.sin(angular_frequency/2) )
    # since sin(x) == x for small x, the above expression
    # evaluates to specsize for angular_frequency == 0.
    spectrum[angular_frequency == 0.0] = specsize
    return spectrum
</pre>
</div>

<p>
A lot of my scientific code ends up quite compact like that. Maybe a hundred lines of dense numeric expressions, plus a few hundred lines of explanations and documentation. The point is, scientific code often does not decompose into easily understood extractable functions.
</p>

<p>
On a related issue, how do you avoid long argument lists in heavily parametrized equations? As Clean Code states, "when a function seems to need more than two or three arguments, it is likely that some of those arguments ought to be wrapped in a class of their own". However, in Matlab in particular, it is quite unusual to create small one-trick classes to encapsulate a few function arguments:
</p>

<div class="org-src-container">
<pre class="src src-octave">classdef SignalBlocks &lt; handle
    properties
        data
        samplerate
        blocksize
        hopsize
    end
    properties (Dependent)
        duration
    end
    methods
        function obj = SignalBlock(data, samplerate, blocksize, hopsize)
            % blocksize and hopsize are optional. What a mess.
            narginchk(2, 4);
            obj.data = data;
            obj.samplerate = samplerate;
            if nargin &gt;= 3
                obj.blocksize = blocksize;
            else
                obj.blocksize = 2048;
            end
            if nargin == 4
                obj.hopsize = hopsize;
            else
                obj.hopsize = 1024;
            end
        end
        function time = get.duration(obj)
            time = length(obj.data)/obj.samplerate;
        end
    end
end
</pre>
</div>

<p>
This is not just cumbersome to write and maintain, it is also slower than passing <code>data</code>, <code>samplerate</code>, <code>blocksize</code>, and <code>hopsize</code> to each function call individually (although the overhead has gotten considerably smaller in newer versions of Matlab). Additionally, there is often a large performance benefit of <i>not</i> extracting every function and <i>not</i> keeping intermediate values in variables. Thus, it's not just readability that is hard to maintain in scientific code. Performance is a problem, too.
</p>

<p>
The sad thing is, I don't know the answer to these questions. There have been a lot of discussions about coding style and code quality in our department lately, with the clear objective to clean up our code. But common code quality criteria don't seem to apply to scientific code all that well.
</p>

<p>
Do you have any idea how to progress from here?
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <link>https://bastibe.de/2016-03-13-code-quality-in-scientific-code.html</link>
  <guid>https://bastibe.de/2016-03-13-code-quality-in-scientific-code.html</guid>
  <pubDate>Sun, 13 Mar 2016 09:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Toren]]></title>
  <description><![CDATA[
<p>
I've been playing a lot of indie games lately. One of them has not been talked about much: <a href="http://toren-game.com/">Toren</a>. Toren is a platformer about a girl that has to climb a tower to defeat a dragon and revive her world. This is probably the least polished game I have played in a long time. Animations are janky, controls are imprecise and clunky, and there are loads of little glitches. Yet, I really enjoyed this.
</p>

<p>
There is something about this world that feels honest to me: As you climb the tower, the child grows from a toddler to an adolescent, and is gradually introduced to more and more mature concepts. I didn't understand much of the iconography of this game, but it felt oddly cathartic to climb this tower of life, and overcome it's challenges.
</p>

<p>
I particularly liked how death played such an integral role in this story and some of the puzzles. The tower is a monument to a dead people, and yet the story and game mechanics are as much about dying as they are about rebirth and not giving up. This is underlined by the wonderful art style of this game, which contrasts vivid colors with brooding, dark architecture.
</p>

<p>
At just about two hours, Toren is not a long game. Instead of exploring one particular game mechanic, it mixes it's game up every few minutes. Every sequence looks different and beautiful, and yet it manages to tell a cohesive and effective story. ★★★★☆
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-games.html">games</a> ]]></description>
  <category><![CDATA[games]]></category>
  <link>https://bastibe.de/2016-01-23-toren.html</link>
  <guid>https://bastibe.de/2016-01-23-toren.html</guid>
  <pubDate>Sat, 23 Jan 2016 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Books of 2015]]></title>
  <description><![CDATA[

<div id="outline-container-org2124857" class="outline-2">
<h2 id="org2124857"><a href="https://www.goodreads.com/book/show/8706185-among-others">Among Others</a>, by Jo Walton</h2>
<div class="outline-text-2" id="text-org2124857">
<p style="float:left;margin:5px;" width="150px">
<img src="https://upload.wikimedia.org/wikipedia/en/d/d1/Among_Others_%28Jo_Walton_novel%29.jpg" alt="Among_Others_%28Jo_Walton_novel%29.jpg" style="float:left;margin:5px;" width="150px">
I don't usually enjoy fantasy novels and their romantic escapism. I much prefer fascinating sci-fi thought experiments. But this book won all the most important awards, so I gave it a shot. What if random chance could be bent a little with creativity, the power of believing in something, and some mysticism? You end up with a world that is richer, more meaningful, and altogether more alive, if you just cared to observe and to appreciate it's beauty. Reading this book left me enchanted and more observant long after I put it down. What a wonderful book!
</p>
</div>
</div>

<div id="outline-container-orga8722ce" class="outline-2">
<h2 id="orga8722ce"><a href="https://www.goodreads.com/book/show/7073.A_Son_of_the_Circus">A Son of the Circus</a>, by John Irving</h2>
<div class="outline-text-2" id="text-orga8722ce">
<p style="float:left;margin:5px;" width="150px">
<img src="https://upload.wikimedia.org/wikipedia/en/e/e7/ASonOfTheCircus.JPG" alt="ASonOfTheCircus.JPG" style="float:left;margin:5px;" width="150px">
This is one of those books that was on my to-read list for months. It starts out as quirky and likeable as you would expect from John Irving. This time, we follow the tale of a Canadian/Indian doctor throughout his life, and his summer vacation in India. But this would not be John Irving if there weren't plenty of colourful characters, astute observations of human strangeness, and a meticulously crafted story. There is no scene in this book that does not serve a purpose, and so many moving parts my mind just boggles at the construction of it all. Yet at the same time, I was regularly laughing out loud. I loved every minute of this!
</p>
</div>
</div>

<div id="outline-container-orgff2f36b" class="outline-2">
<h2 id="orgff2f36b"><a href="https://www.goodreads.com/book/show/6597651-the-windup-girl">The Windup Girl</a>, by Paolo Bacigalupi</h2>
<div class="outline-text-2" id="text-orgff2f36b">
<p style="float:left;margin:5px;" width="150px">
<img src="https://upload.wikimedia.org/wikipedia/en/1/1f/Wind_up.jpg" alt="Wind_up.jpg" style="float:left;margin:5px;" width="150px">
The whole world changed in the near future, when gasoline is a rare luxury, sea levels have risen and swallowed all the coastal cities, and man-made scourges have devastated most crops. And now it's not just humans that populate our urbanized world, but so too are our inventions, artificial humans called "windups" for their stutter-stop movements. But at the core, both humans and windups struggle for the same security, prosperity as ever. Such an inventive world, so much vivid creativity, social commentary, in this human struggle to not destroy ourselves.
</p>
</div>
</div>

<div id="outline-container-org8f189c2" class="outline-2">
<h2 id="org8f189c2"><a href="https://www.goodreads.com/book/show/629.Zen_and_the_Art_of_Motorcycle_Maintenance">Zen and the art of motorcycle maintenance</a>, by Robert Pirsig</h2>
<div class="outline-text-2" id="text-org8f189c2">
<p style="float:left;margin:5px;" width="150px">
<img src="https://upload.wikimedia.org/wikipedia/en/8/85/Zen_motorcycle.jpg" alt="Zen_motorcycle.jpg" style="float:left;margin:5px;" width="150px">
This is about equal parts a motorcycle journey of a father and his son across the US, and a dive into another man's discoveries of philosophy. To be honest, I liked this book more for it's character descriptions and travelling adventures than it's philosophy. I am really conflicted about putting this book on this list at all, but I kept thinking about this long after I finished reading it, so I guess this had a bigger influence on me than I realized.
</p>
</div>
</div>

<div id="outline-container-orgad43f93" class="outline-2">
<h2 id="orgad43f93">Nexus/Crux/Apex, Rad/Blue/Green Mars, The Martian, The Three-Body Problem</h2>
<div class="outline-text-2" id="text-orgad43f93">
<p>
What happens when you take today's world, and add nanotech brain upgrades (Nexus/Crux/Apex), or strand a lone scientist on Mars (The Martian), or send a large number of people to found a new colony on Mars (Red/Blue/Green Mars), or suddenly make contact with Aliens (The Three-Body Problem)? This what-if is what Science Fiction does best: Take this little what-if, and spin a gripping yarn from that. These books inspired me, made me think, were incredibly thrilling, but they did not have a lasting impact. Still well worth a read if you like Science Fiction, though.
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-books.html">books</a> ]]></description>
  <category><![CDATA[books]]></category>
  <link>https://bastibe.de/2016-01-06-books-of-2015.html</link>
  <guid>https://bastibe.de/2016-01-06-books-of-2015.html</guid>
  <pubDate>Wed, 06 Jan 2016 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Calling Matlab from Python]]></title>
  <description><![CDATA[
<p>
For my latest experiments, I needed to run both Python functions and Matlab functions as part of the same program. As I <a href="http://bastibe.de/2015-10-29-matlab-engine-leaks.html">noted earlier</a>, Matlab includes the <a href="http://mathworks.com/help/matlab/matlab-engine-for-python.html">Matlab Engine for Python</a> (MEfP), which can call Matlab functions from Python. Before I knew about this, I created <a href="https://github.com/bastibe/transplant">Transplant</a>, which does the very same thing. So, how do they compare?
</p>

<div id="outline-container-org87e0c1c" class="outline-2">
<h2 id="org87e0c1c">Usage</h2>
<div class="outline-text-2" id="text-org87e0c1c">
<p>
As it's name suggests, Matlab is a <b>mat</b>rix <b>lab</b>oratory, and matrices are the most important data type in Matlab. Since matrices don't exist in plain Python, the MEfP implements it's own as <code>matlab.double</code> et al., and you have to convert any data you want to pass to Matlab into one of those. In contrast, Transplant recognizes the fact that Python does in fact know a really good matrix engine called <a href="http://scipy.org/">Numpy</a>, and just uses that instead.
</p>

<pre class="example" id="org10399bc">
       Matlab Engine for Python        |              Transplant
---------------------------------------|---------------------------------------
import numpy                           | import numpy
import matlab                          | import transplant
import matlab.engine                   |
                                       |
eng = matlab.engine.start_matlab()     | eng = transplant.Matlab()
numpy_data = numpy.random.randn(100)   | numpy_data = numpy.random.randn(100)
list_data = numpy_data.tolist()        |
matlab_data = matlab.double(list_data) |
data_sum = eng.sum(matlab_data)        | data_sum = eng.sum(numpy_data)
</pre>

<p>
Aside from this difference, both libraries work almost identical. Even the handling of the number of output arguments is (accidentally) almost the same:
</p>

<pre class="example" id="org2579892">
       Matlab Engine for Python        |              Transplant
---------------------------------------|---------------------------------------
eng.max(matlab_data)                   | eng.max(numpy_data)
&gt;&gt;&gt; 4.533                              | &gt;&gt;&gt; [4.533 537635]
eng.max(matlab_data, nargout=1)        | eng.max(numpy_data, nargout=1)
&gt;&gt;&gt; 4.533                              | &gt;&gt;&gt; 4.533
eng.max(matlab_data, nargout=2)        | eng.max(numpy_data, nargout=2)
&gt;&gt;&gt; (4.533, 537635.0)                  | &gt;&gt;&gt; [4.533 537635]
</pre>

<p>
Similarly, both libraries can interact with Matlab objects in Python, although the MEfP can't access object properties:
</p>

<pre class="example" id="org6693143">
       Matlab Engine for Python        |              Transplant
---------------------------------------|---------------------------------------
f = eng.figure()                       | f = eng.figure()
eng.get(f, 'Position')                 | eng.get(f, 'Position')
&gt;&gt;&gt; matlab.double([[ ... ]])           | &gt;&gt;&gt; array([[ ... ]])
f.Position                             | f.Position
&gt;&gt;&gt; AttributeError                     | &gt;&gt;&gt; array([[ ... ]])
</pre>

<p>
There are a few small differences, though:
</p>

<ul class="org-ul">
<li>Function documentation in the MEfP is only available as <code>eng.help('funcname')</code>. Transplant will populate a function's <code>__doc__</code>, and thus documentation tools like IPython's <code>?</code> operator just work.</li>
<li>Transplant converts empty matrices to <code>None</code>, whereas the MEfP represents them as <code>matlab.double([])</code>.</li>
<li>Transplant represents <code>dict</code> as <code>containers.Map</code>, while the MEfP uses <code>struct</code> (the former is more correct, the latter arguable more useful).</li>
<li>If the MEfP does not know <code>nargout</code>, it assumes <code>nargout=1</code>. Transplant uses <code>nargout(func)</code> or returns whatever the function writes into <code>ans</code>.</li>
<li>The MEfP can't return non-scalar structs, such as the return value of <code>whos</code>. Transplant can do this.</li>
<li>The MEfP can't return anonymous functions, such as <code>eng.eval('@(x, y) x&gt;y')</code>. Transplant can do this.</li>
</ul>
</div>
</div>

<div id="outline-container-orgb087e4f" class="outline-2">
<h2 id="orgb087e4f">Performance</h2>
<div class="outline-text-2" id="text-orgb087e4f">
<p>
The time to start a Matlab instance is shorter in MEfP (3.8 s) than in Transplant (6.1 s). But since you're doing this relatively seldomly, the difference typically doesn't matter too much.
</p>

<p>
More interesting is the time it takes to call a Matlab function from Python. Have a look:
</p>


<figure id="org8d35fdb">
<img src="http://bastibe.de/static/2015-11/execution%20time.png" alt="execution%20time.png">

</figure>

<p>
This is running <code>sum(randn(n,1))</code> from Transplant, the MEfP, and in Matlab itself. As you can see, the MEfP is a constant factor of about 1000 slower than Matlab. Transplant is a constant factor of about 100 slower than Matlab, but always takes at least 0.05 s.
</p>

<p>
There is a gap of about a factor of 10 between Transplant and the MEfP. In practice, this gap is highly significant! In my particular use case, I have <a href="http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/doc/voicebox/fxpefac.html">a function</a> that takes about one second of computation time for an audio signal of ten seconds (half a million values). When I call this function with Transplant, it takes about 1.3 seconds. With MEfP, it takes 4.5 seconds.
</p>

<p>
Transplant spends its time serializing the arguments to JSON, sending that JSON over <a href="http://zeromq.org/">ZeroMQ</a> to Matlab, and parsing the JSON there. Well, to be honest, only the parsing part takes any significant time, overall. While it might seem onerous to serialize everything to JSON, this architecture allows Transplant to run over a network connection.
</p>

<p>
It is a bit baffling to me that MEfP manages to be slower than <i>that</i>, despite being written in C. Looking at the number of function calls in the profiler, the MEfP calls 25 functions (!) on each value (!!) of the input data. This is a shockingly inefficient way of doing things.
</p>
</div>
</div>

<div id="outline-container-org9ae3522" class="outline-2">
<h2 id="org9ae3522">TL;DR</h2>
<div class="outline-text-2" id="text-org9ae3522">
<p>
It used to be very difficult to work in a mixed-language environment, particularly with one of those languages being Matlab. Nowadays, this has thankfully gotten much easier. Even Mathworks themselves have stepped up their game, and can interact with Python, C, Java, and FORTRAN. But their interface to Python does leave something to be desired, and there are better alternatives available.
</p>

<p>
If you want to try Transplant, just head over to <a href="https://github.com/bastibe/transplant">Github</a> and use it. If you find any bugs, feature requests, or improvements, please let me know in the Github issues.
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-matlab.html">matlab</a> <a href="https://bastibe.de/tag-python.html">python</a> ]]></description>
  <category><![CDATA[matlab]]></category>
  <category><![CDATA[python]]></category>
  <link>https://bastibe.de/2015-11-03-matlab-engine-performance.html</link>
  <guid>https://bastibe.de/2015-11-03-matlab-engine-performance.html</guid>
  <pubDate>Tue, 03 Nov 2015 15:05:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Massive Memory Leak in the Matlab Engine for Python]]></title>
  <description><![CDATA[
<p>
As of Matlab 2014b, Matlab includes a <a href="http://mathworks.com/help/matlab/matlab-engine-for-python.html">Python module</a> for calling Matlab code from Python. This is how you use it:
</p>

<div class="org-src-container">
<pre class="src src-python">import numpy
import matlab
import matlab.engine

eng = matlab.engine.start_matlab()
random_data = numpy.random.randn(100)
# convert Numpy data to Matlab:
matlab_data = matlab.double(random_data.tolist())
data_sum = eng.sum(matlab_data)
</pre>
</div>

<p>
You can call any Matlab function on <code>eng</code>, and you can access any Matlab workspace variable in <code>eng.workspace</code>. As you can see, the Matlab Engine is not Numpy-aware, and you have to convert all your Numpy data to Matlab <code>double</code> before you can call Matlab functions with it. Still, it works pretty well.
</p>

<p>
Recently, I ran a rather large experiment set, where I had a set of four functions, two in Matlab, two in Python, and called each of these functions a few thousand times with a bunch of different data to see how they performed.
</p>

<p>
While doing that I noticed that my Python processes were growing larger and larger, until they consumed all my memory and a sizeable chunk of my swap as well. I couldn't find any reason for this. None of my Python code cached anything, and the sum total of all global variables did not amount to anything substantial.
</p>

<p>
Enter <a href="http://pythonhosted.org/Pympler/index.html">Pympler</a>, a memory analyzer for Python. Pympler is an amazing library for introspecting your program's memory. Among its many features, it can list the biggest objects in your running program:
</p>

<div class="org-src-container">
<pre class="src src-python">from pympler import muppy, summary
summary.print_(summary.summarize(muppy.get_objects()))
</pre>
</div>

<pre class="example" id="org6040c44">
                                      types |   # objects |   total size
=========================================== | =========== | ============
                        &lt;class 'array.array |        1076 |      2.77 GB
                                &lt;class 'str |       42839 |      7.65 MB
                               &lt;class 'dict |        8604 |      5.43 MB
                      &lt;class 'numpy.ndarray |          48 |      3.16 MB
                               &lt;class 'code |       14113 |      1.94 MB
                               &lt;class 'type |        1557 |      1.62 MB
                               &lt;class 'list |        3158 |      1.38 MB
                                &lt;class 'set |        1265 |    529.72 KB
                              &lt;class 'tuple |        5129 |    336.98 KB
                              &lt;class 'bytes |        2413 |    219.48 KB
                            &lt;class 'weakref |        2654 |    207.34 KB
            &lt;class 'collections.OrderedDict |          65 |    149.85 KB
                 &lt;class 'wrapper_descriptor |        1676 |    130.94 KB
  &lt;class 'traitlets.traitlets.MetaHasTraits |         107 |    123.55 KB
                  &lt;class 'getset_descriptor |        1738 |    122.20 KB
</pre>

<p>
Now that is interesting. Apparently, I was lugging around close to three gigabytes worth of bare-Python <code>array.array</code>. And these are clearly not Numpy arrays, since those would show up as <code>numpy.ndarray</code>. But I couldn't find any of these objects in my workspace.
</p>

<p>
So let's get a reference to one of these objects, and see who they belong to. This can also be done with Pympler, but I prefer the way <a href="http://mg.pov.lt/objgraph/">objgraph</a> does it:
</p>

<div class="org-src-container">
<pre class="src src-python">import array
# get a list of all objects known to Python:
all_objects = muppy.get_objects()
# sort out only `array.array` instances:
all_arrays = [obj for obj in all_objects if isinstance(obj, array.array)]

import objgraph
objgraph.show_backrefs(all_arrays[0], filename='array.png')
</pre>
</div>


<figure id="org50730ab">
<img src="http://bastibe.de/static/2015-10/array.png" alt="array.png">

</figure>

<p>
It seems that the <code>array.array</code> object is part of a <code>matlab.double</code> instance which is not referenced from anywhere but <code>all_objects</code>. A memory leak.
</p>

<p>
After a bit of experimentation, I found the culprit. To illustrate, here's an example: The function <code>leak</code> passes some data to Matlab, and calculates a float. Since the variables are not used outside of <code>leak</code>, and the function does not return anything, all variables within the function should get deallocated when <code>leak</code> returns.
</p>

<div class="org-src-container">
<pre class="src src-python">def leak():
    test_data = numpy.zeros(1024*1024)
    matlab_data = matlab.double(test_data.tolist())
    eng.sum(matlab_data)
</pre>
</div>

<p>
Pympler has another great feature that can track allocations. The <code>SummaryTracker</code> will track and display any allocations between calls to <code>print_diff()</code>. This is very useful to see how much memory was used during the call to <code>leak</code>:
</p>

<div class="org-src-container">
<pre class="src src-python">from pympler import tracker
tr = tracker.SummaryTracker()
tr.print_diff()
leak()
tr.print_diff()
</pre>
</div>

<pre class="example" id="org4781114">
                     types |   # objects |   total size
========================== | =========== | ============
       &lt;class 'array.array |           1 |      8.00 MB
...
</pre>

<p>
And there you have it. Note that this leak is not the Numpy array <code>test_data</code> and it is not the matlab array <code>matlab_data</code>. Both of these are garbage collected correctly. But <b>the Matlab Engine for Python will leak any data you pass to a Matlab function</b>.
</p>

<p>
This data is not referenced from anywhere within Python, and is counted as <i>leaked</i> by <code>objgraph</code>. In other words, the C code inside the Matlab Engine for Python copies all passed data into it's internal memory, but never frees that memory. Not even if you quit the Matlab Engine, or <code>del</code> all Python references to it. Your only option is to restart Python.
</p>

<p>
<b>Postscriptum</b>
</p>

<p>
I since posted a bug report on Mathworks, and received a patch that fixes the problem. Additionally, Mathworks said that the problem only occurs on Linux.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-matlab.html">matlab</a> ]]></description>
  <category><![CDATA[matlab]]></category>
  <link>https://bastibe.de/2015-10-29-matlab-engine-leaks.html</link>
  <guid>https://bastibe.de/2015-10-29-matlab-engine-leaks.html</guid>
  <pubDate>Thu, 29 Oct 2015 12:18:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[OS X Finder Woes]]></title>
  <description><![CDATA[

<figure id="org5597974">
<img src="http://bastibe.de/static/2015-10/Mac.png" alt="Mac.png">

</figure>

<p>
The Mac. It used to be the most streamlined, thought-through general computing device on the market.
</p>

<p>
Even it's file management used to be top-notch. There were many cool little touches. One particularly useful feature was the <i>Proxy Icon</i>&#x2013;if a window displayed a file's content, that file's icon would show up in the window's title. And you could drag that icon directly onto a thumb drive or email, without having to use the Finder. But the Finder, too, had many neat little features. I loved the fact that when you renamed a file in an alphabetically sorted file list, Finder would not immediately re-shuffle it to its new location, but would wait half a second before doing so. When renaming multiple files, this was really useful, since you could go through them one by one and rename them, simply by pressing arrow keys and return.
</p>

<p>
But as you might have guessed from my use of the past tense, these golden days are gone. The Finder used to know a JPEG from a ZIP regardless of file extension. Now it doesn't any more. The Proxy Icon is still draggable, but it will create an alias instead of a copy&#x2013;perfectly useless on a thumb drive or in an email.
</p>

<p>
And with the newest version of OS X, El Capitan, they finally blew it for me. Before, even though the Finder inexplicably never had the ability to cut and paste files, you could always install programs like <a href="http://totalfinder.binaryage.com/">TotalFinder</a> to fix that. Not so with El Capitan. The Finder now is holy land, and can not be touched any more by third parties. So no more cut and paste, no more un-hiding system files. No more side-by-side Finder tabs. And brand new with El Capitan as well: No more waiting after renaming. Now, when you rename a file, it is immediately re-sorted to its new position, thus making renaming multiple files terribly inconvenient.
</p>

<p>
So, good bye OS X. I updated my work laptop first, and I regret it. I never regretted an OS X update before. My home machine is not going to get the update. It is honestly sad to see my once-beloved Mac platform becoming worse and worse and worse with every new release.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-macos.html">macos</a> <a href="https://bastibe.de/tag-ui.html">ui</a> ]]></description>
  <category><![CDATA[macos]]></category>
  <category><![CDATA[ui]]></category>
  <link>https://bastibe.de/2015-10-16-finder-woes.html</link>
  <guid>https://bastibe.de/2015-10-16-finder-woes.html</guid>
  <pubDate>Fri, 16 Oct 2015 09:51:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Changing File Creation Dates in OSX]]></title>
  <description><![CDATA[
<p>
On my last vacation, I have taken a bunch of pictures, and a bunch of video. The problem is, I hadn't used the video camera in a long time, and it believed that all it's videos were taken on the first of January 2012. So in order for the pictures to show up correctly in my picture library, I wanted to correct that.
</p>

<p>
For images, this is relatively easy: Most picture libraries support some kind of bulk date changes, and there are a bunch of <a href="http://www.sentex.net/~mwandel/jhead/">command</a> <a href="http://owl.phy.queensu.ca/~phil/exiftool/">line</a> <a href="http://www.exiv2.org/#util">utilities</a> that can do it, too. But none of these tools work for video (exiftool claims be able to do that, but I couldn't get it to work).
</p>

<p>
So instead, I went about to change the file creation date of the actual video files. And it turns out, this is surprisingly hard! The thing is, most Unix systems (a Mac is technically a Unix system) don't even know the concept of a file creation date. Thus, most Unix utilities, including most programming languages, don't know how to deal with that, either.
</p>

<p>
If you have XCode installed, this will come with <code>SetFile</code>, a command line utility that can change file creation dates. Note that <code>SetFile</code> can change <i>either</i> the file creation date, <i>or</i> the file modification date, but not both at the same time, as any normal Unix utility would. Also note that <code>SetFile</code> expects dates in American notation, which is about as nonsensical as date formats come.
</p>

<p>
Anyway, here's a small Python script that changes the file creation date (but not the time) of a bunch of video files:
</p>

<div class="org-src-container">
<pre class="src src-python">import os.path
import os
import datetime
# I want to change the dates on the files GOPR0246.MP4-GOPR0264.MP4
for index in range(426, 465):
    filename = 'GOPR0{}.MP4'.format(index)
    # extract old date:
    date = datetime.datetime.fromtimestamp(os.path.getctime(filename))
    # create a new date with the same time, but on 2015-08-22
    new_date = datetime.datetime(2015,  8, 22, date.hour, date.minute, date.second)
    # set the file creation date with the "-d" switch, which presumably stands for "dodification"
    os.system('SetFile -d "{}" {}'.format(new_date.strftime('%m/%d/%Y %H:%M:%S'), filename))
    # set the file modification date with the "-m" switch
    os.system('SetFile -m "{}" {}'.format(new_date.strftime('%m/%d/%Y %H:%M:%S'), filename))
</pre>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> <a href="https://bastibe.de/tag-macos.html">macos</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <category><![CDATA[macos]]></category>
  <link>https://bastibe.de/2015-10-03-changing-file-creation-dates.html</link>
  <guid>https://bastibe.de/2015-10-03-changing-file-creation-dates.html</guid>
  <pubDate>Sat, 03 Oct 2015 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Numpy Broadcasting Rules]]></title>
  <description><![CDATA[
<p>
They say that all arithmetic operations in Numpy behave like their element-wise cousins in Matlab. This is wrong, and seriously tripped me up last week.
</p>

<p>
In particular, this is what happens when you multiply an array with a matrix[1] in Numpy:
</p>

<pre class="example" id="org4b339e1">
     [[  1],           [[1, 2, 3],       [[ 1,    2,   3],
      [ 10],       *    [4, 5, 6],   =    [ 40,  50,  60],
      [100]]            [7, 8, 9]]        [700, 800, 900]]

 [  1,  10, 100]       [[1, 2, 3],       [[  1,  20, 300],
        OR         *    [4, 5, 6],   =    [  4,  50, 600],
[[  1,  10, 100]]       [7, 8, 9]]        [  7,  80, 900]]
</pre>

<p>
They behave as if each row was evaluated separately, and singular dimensions are repeated where necessary. It helps to think about them as row-wise, instead of element-wise. This is particularly important in the second example, where the <i>whole</i> 1d-array is multiplied with <i>every row</i> of the 2d-array.
</p>

<p>
Note that this is <i>not</i> equivalent to multiplying every <i>element</i> as in <code>[a[n]*b[n] for n in range(len(a))]</code>. I guess that's why this is called <i>broadcasting</i>, and not <i>element-wise</i>.
</p>

<p>
[1] "matrix" here refers to a 2-d <code>numpy.array</code>. There is also a <code>numpy.matrix</code>, where multiplication is matrix multiplication, but this is not what I'm talking about.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-python.html">python</a> ]]></description>
  <category><![CDATA[python]]></category>
  <link>https://bastibe.de/2015-09-29-numpy-broadcasting-rules.html</link>
  <guid>https://bastibe.de/2015-09-29-numpy-broadcasting-rules.html</guid>
  <pubDate>Tue, 29 Sep 2015 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Python Numeric Performance]]></title>
  <description><![CDATA[
<p>
Recently, I was working on a dynamic programming algorithm that involves a lot of number crunching in nested loops. The algorithm looks like this:
</p>

<div class="org-src-container">
<pre class="src src-python">def y_change_probability_python(oct_per_sec):
    """ ... """
    b = 1.781
    mu = -0.301
    return 1/(2*b)*math.exp(-abs(oct_per_sec-mu)/b)

def y_idx_range_python(y_idx, max_y_factor, height):
    """ ... """
    y = (y_idx/height)*(max_y-min_y)+min_y
    y_lo = max(y/max_y_factor, min_y)
    y_hi = min(y*max_y_factor, max_y)
    y_lo_idx = int((y_lo-min_y)/(max_y-min_y)*height)
    y_hi_idx = int((y_hi-min_y)/(max_y-min_y)*height)
    return y_lo_idx, y_hi_idx

def find_tracks_python(cost_matrix, delta_x):
    """ ... """
    tracks = np.zeros(correlogram.shape, dtype=np.int64)
    cum_cost = np.zeros(correlogram.shape)

    max_y_factor = (2**5)**(delta_x)
    height = correlogram.shape[1]

    probabilities = np.empty((height, height))
    for y_idx in range(height):
        y = (y_idx/height)*(max_y-min_y)+min_y
        for y_pre_idx in range(*y_idx_range_numba(y_idx, max_y_factor, height)):
            y_pre = (y_pre_idx/height)*(max_y-min_y)+min_y
            doubles_per_x = math.log2((y/y_pre)**(1/delta_x))
            probabilities[y_idx, y_pre_idx] = y_change_probability_numba(doubles_per_x)

    for x_idx, cost_column in enumerate(cost_matrix):
        if x_idx == 0:
            cum_cost[x_idx] = cost_column
            continue
        for y_idx, cost in enumerate(cost_column):
            for y_pre_idx in range(*y_idx_range_numba(y_idx, max_y_factor, height)):
                weighted_cum_cost = cum_cost[x_idx-1, y_pre_idx] + cost*probabilities[y_idx, y_pre_idx]
                if weighted_cum_cost &gt; cum_cost[x_idx, y_idx]:
                    cum_cost[x_idx, y_idx] = weighted_cum_cost
                    tracks[x_idx, y_idx] = y_pre_idx
            cum_cost[x_idx, y_idx] = cum_cost[x_idx-1, tracks[x_idx, y_idx]] + cost

    return tracks, cum_cost
</pre>
</div>

<p>
I'm not going into the details of what this algorithm does, but note that it iterates over every column and row of the matrix <code>cost_matrix</code>, and then iterates over another range <code>previous_y_range</code> for each of the values in <code>cost_matrix</code>. On the way, it does a lot of basic arithmetic and some algebra.
</p>

<p>
The problem is, this is very slow. For a \(90 \times 200\) <code>cost_matrix</code>, this takes about 260 ms. Lots of loops? Lots of simple mathematics? Slow? That sounds like a perfect match for <a href="http://www.numpy.org/">Numpy</a>!
</p>

<p>
If you can express your code in terms of linear algebra, Numpy will execute them in highly-optimized C code. The problem is, translating loops into linear algebra is not always easy. In this case, it took some effort:
</p>

<div class="org-src-container">
<pre class="src src-python">def y_change_probability_numpy(doubles_per_x):
    """ ... """
    b = 1.781
    mu = -0.301
    return 1/(2*b)*np.exp(-np.abs(doubles_per_x-mu)/b)

def find_frequency_tracks_numpy(cost_matrix, delta_x):
    """ ... """
    tracks = np.zeros(cost_matrix.shape, dtype=np.int)
    cum_cost = np.zeros(cost_matrix.shape)

    max_y_factor = (2**5)**(delta_t) # allow at most 5 octaves per second (3 sigma)
    height = cost_matrix.shape[1]

    # pre-allocate probabilities matrix as minus infinity. This matrix
    # will be sparsely filled with positive probability values, and
    # empty values will have minus infinite probability.
    probabilities = -np.ones((height, height))*np.inf
    for y_idx in range(probabilities.shape[0]):
        y = (y_idx/height)*(max_y-min_y)+min_y
        y_pre_idx = np.arange(int((max(y/max_y_factor, min_y)-min_y)/(max_y-min_y)*height),
                              int((min(y*max_y_factor, max_y)-min_y)/(max_y-min_y)*height))
        y_pre = (y_pre_idx/height)*(max_y-min_y)+min_y
        doubles_per_x = np.log2((y/y_pre)**(1/delta_x))
        probabilities[y_idx, y_pre_idx] = y_change_probability(doubles_per_x)

    cum_cost[0] = cost_matrix[0]
    for x_idx in range(1, len(cost_matrix)):
        cost_column = cost_matrix[x_idx:x_idx+1] # extract cost_column as 2d-vector!
        weighted_cum_cost = cum_cost[x_idx-1] + cost_column.T*probabilities
        tracks[x_idx] = np.argmax(weighted_cum_cost, axis=1)
        cum_cost[x_idx] = cum_cost[x_idx-1, tracks[x_idx]] + cost_column

    return tracks, cum_corrs
</pre>
</div>

<p>
This code does not look much like the original, but calculates exactly the same thing. This takes about 15 ms for a \(90 \times 200\) <code>cost_matrix</code>, which is about 17 times faster than the original code! Yay Numpy! And furthermore, this code is arguably more readable than the original, since it is written at a higher level of abstraction.
</p>

<p>
Another avenue for performance optimization is <a href="http://numba.pydata.org/">Numba</a>. Numba applies dark and powerful magic to compile humble Python functions into blazingly fast machine code. It is proper magic, if you ask me. Simply add an innocuous little decorator to your functions, and let Numba do it's thing. If all goes well, your code will work just as before, except with unheard-of performance:
</p>

<div class="org-src-container">
<pre class="src src-python">@jit(numba.float64(numba.float64), nopython=True)
def y_change_probability_numba(doubles_per_x):
    ...

@jit((numba.int64, numba.float64, numba.int64), nopython=True)
def y_idx_range_numba(y_idx, max_y_factor, height):
    ...

@jit((numba.float64[:,:], numba.float64), nopython=True)
def find_tracks_numba(cost_matrix, delta_t):
    ...
</pre>
</div>

<p>
However, Numba is no silver bullet, and does not support all of Python yet. In the present case, it is missing support for <code>enumerate</code> for Numpy matrices. Thus, I had to rewrite the first two loops like this:
</p>

<div class="org-src-container">
<pre class="src src-python"># python version
for x_idx, cost_column in enumerate(cost_matrix):
    ...

# numba version
for x_idx in range(len(cost_matrix)):
    cost_column = cost_matrix[x_idx]
    ...
</pre>
</div>

<p>
Another area that proved problematic is N-D slice writing. Instead of using expressions like <code>m1[x,y:y+3] = m2</code>, you have to write <code>for idx in range(3): m1[x,y+idx] = m2[idx]</code>. Not a difficult transformation, but it basically forced me to unroll all the nice vectorized code of the Numpy version back to their original pure-Python form. That said, Numba is getting better and better, and many constructs that used to be uncompilable (<code>yield</code>) are not a problem any more.
</p>

<p>
Anyway, with that done, the above code went down from 260 ms to 2.2 ms. This is a 120-fold increase in performance, and still seven times faster than Numpy, with minimal code changes. This is proper magic!
</p>

<p>
So why wouldn't you just always use Numba? After all, when it comes down to raw performance, Numba is the clear winner. The big difference between performance optimization using Numpy and Numba is that properly vectorizing your code for Numpy often reveals simplifications and abstractions that make it easier to reason about your code. Numpy forces you to think in terms of vectors, matrices, and linear algebra, and this often makes your code <i>more beautiful</i>. Numba on the other hand often requires you to make your code <i>less beautiful</i> to conform to it's subset of compilable Python.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-python.html">python</a> ]]></description>
  <category><![CDATA[python]]></category>
  <link>https://bastibe.de/2015-09-28-python-performance.html</link>
  <guid>https://bastibe.de/2015-09-28-python-performance.html</guid>
  <pubDate>Mon, 28 Sep 2015 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Matlab and Audio Files]]></title>
  <description><![CDATA[
<p>
So I wanted to work with audio files in Matlab. In the past, Matlab could only do this with <code>auread</code> and <code>wavread</code>, which can read <i>*.au</i> and <i>*.wav</i> files. With 2012b, Matlab introduced <a href="http://mathworks.com/help/matlab/ref/audioread.html"><code>audioread</code></a>, which claims to support <i>*.wav</i>, <i>*.ogg</i>, <i>*.flac</i>, <i>*.au</i>, <i>*.mp3</i>, and <i>*.mp4</i>, and simultaneously deprecated <code>auread</code> and <code>wavread</code>.
</p>

<p>
Of these file formats, only <i>*.au</i> is capable of storing more than 4 Gb of audio data. But the documentation is actually wrong: <code>audioread</code> can <i>actually</i> read more data formats than documented: it reads <i>*.w64</i>, <i>*.rf64</i>, and <i>*.caf</i> no problem. And these can store more than 4 Gb as well.
</p>

<p>
It's just that, while <code>audioread</code> supports all of these nice file formats, <a href="http://mathworks.com/help/matlab/ref/audiowrite.html"><code>audiowrite</code></a> is more limited, and only supports <i>*.wav</i>, <i>*.ogg</i>, <i>*.flac</i>, and <i>*.mp4</i>. And it does not support any undocumented formats, either. So it seems that there is no way of writing files larger than 4 Gb. But for the time being, <code>auwrite</code> is still available, even though deprecated. I tried it, though, and it didn't finish writing 4.8 Gb in half an hour.
</p>

<p>
In other words, Matlab is incapable of writing audio files larger than 4 Gb. It just can't do it.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-matlab.html">matlab</a> <a href="https://bastibe.de/tag-audio.html">audio</a> ]]></description>
  <category><![CDATA[matlab]]></category>
  <category><![CDATA[audio]]></category>
  <link>https://bastibe.de/2015-04-22-matlab-and-audio-files.html</link>
  <guid>https://bastibe.de/2015-04-22-matlab-and-audio-files.html</guid>
  <pubDate>Wed, 22 Apr 2015 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Unicode and Matlab on the command line]]></title>
  <description><![CDATA[
<p>
As per the latest <a href="http://stackoverflow.com/research/developer-survey-2015#techSuper-dreaded">Stackoverflow Developer Survey</a>, Matlab is one of <i>the</i> most dreaded tools out there. I run into Matlab-related trouble daily. In all honesty, I have never seen a programming language as user-hostile and as badly designed as this.
</p>

<p>
So here is today's problem: When run from the command line, Matlab does not render unicode characters (on OSX).
</p>

<p>
I say "(on OSX)", because on Windows, it does not print a damn thing. Nope, no <code>disp</code> output for Windows users.
</p>

<p>
More analysis: It's not that Matlab does not render unicode characters at all when run from the command line. Instead, it renders them as <code>0x1a</code> aka <code>SUB</code> aka <i>substitute character</i>. In other words, it tries to render unicode as ASCII (which doesn't work), and then replaces all non-ASCII characters with <code>SUB</code>. This is actually reasonable if Matlab were running on a machine that can't handle unicode. This is not a correct assessment of post-90s Macs, though.
</p>

<p>
To see why Matlab would do such a dastardly deed, you can use <code>feature('locale')</code> to get information about the encoding Matlab uses. On Windows and OS X, this defaults to either <code>ISO-8859-1</code> (when your locale is pure <code>de_DE</code> or <code>en_US</code>) or <code>US-ASCII</code>, if it is something impure. In my case, German dates but English text. Because <code>US-ASCII</code> is obviously the most all-encompassing choice for such mixed-languages environments.
</p>

<p>
But luckily, there is help. Matlab has a widely documented (not) and easily discoverable (not) configuration option to change this: To change Matlab's encoding settings, edit <code>%MATLABROOT%/bin/lcdata.xml</code>, and look for the entry for your locale. For me, this is one of
</p>

<div class="org-src-container">
<pre class="src src-xml">&lt;locale name="de_DE" encoding="ISO-8859-1" xpg_name="de_DE.ISO8859-1"&gt; ...
&lt;locale name="en_US" encoding="ISO-8859-1" xpg_name="en_US.ISO8859-1"&gt; ...
</pre>
</div>

<p>
In order to make Matlab's encoding default to UTF-8, change the entry for your locale to
</p>

<div class="org-src-container">
<pre class="src src-xml">&lt;locale name="de_DE" encoding="UTF-8" xpg_name="de_DE.UTF-8"&gt; ...
&lt;locale name="en_US" encoding="UTF-8" xpg_name="en_US.UTF-8"&gt; ...
</pre>
</div>

<p>
With that, Matlab will print UTF-8 to the terminal.
</p>

<p>
You still can't type unicode characters to the command prompt, of course. But who would want that anyway, I dare ask. Of course, what with Matlab being basically free, and frequently updated, we can forgive such foibles easily&#x2026;
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-matlab.html">matlab</a> ]]></description>
  <category><![CDATA[matlab]]></category>
  <link>https://bastibe.de/2015-04-15-unicode-in-the-matlab-command-line.html</link>
  <guid>https://bastibe.de/2015-04-15-unicode-in-the-matlab-command-line.html</guid>
  <pubDate>Wed, 15 Apr 2015 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Decisions in Pillars of Eternity]]></title>
  <description><![CDATA[
<p>
Early on in <a href="https://en.wikipedia.org/wiki/Pillars_of_Eternity">Pillars of Eternity</a>, you are tasked to kill one of two characters: Either you kill King Rethoric, who executed many innocent people, or you kill Rolsc, the leader of the rebellion. This is an interesting moral choice, but it is also profoundly sad that the game presents killing either of them as the only resolution to this conflict.
</p>

<p>
It got me thinking. In the real world, I would not consider killing to be an option, ever. But in the game, you have to play by the game's rules. And furthermore, you can't just walk away and have the two characters duke it out amongst themselves: The whole game is built around the player, and without the player's interaction, the game world doesn't evolve.
</p>

<p>
Thus, this conflict won't resolve itself, and the player is forced to kill. I wish there were a diplomatic option, or a way of fixing the underlying problem so the two characters are not at odds any more. I fear how these choices in video games might influence our perceptions of everyday choices, and crave for video games that offer interesting choices that do not revolve around murder.
</p>

<p>
From what I hear, Planescape Torment did offer such choices. As did many of <a href="https://en.wikipedia.org/wiki/Gone_Home">my</a> <a href="https://en.wikipedia.org/wiki/The_Stanley_Parable">favorite</a> <a href="https://en.wikipedia.org/wiki/X-Plane_%2528simulator%2529">games</a> <a href="https://en.wikipedia.org/wiki/Civilization_V">of</a> <a href="https://en.wikipedia.org/wiki/The_Wolf_Among_Us">all</a> <a href="https://en.wikipedia.org/wiki/The_Witcher_%2528video_game%2529">times</a>.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-games.html">games</a> ]]></description>
  <category><![CDATA[games]]></category>
  <link>https://bastibe.de/2015-04-12-decisions-in-poe.html</link>
  <guid>https://bastibe.de/2015-04-12-decisions-in-poe.html</guid>
  <pubDate>Sun, 12 Apr 2015 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Julia First Impressions]]></title>
  <description><![CDATA[
<blockquote>
<p>
Julia is a high-level dynamic programming language designed to address the requirements of high-performance numerical and scientific computing while also being effective for general purpose programming. —<a href="https://en.wikipedia.org/wiki/Julia_%28programming_language%29">Wikipedia</a>
</p>
</blockquote>

<p>
In other words, it is supposed to be as fast as C, as practical as Python, and as scientific as Matlab. The next step in mainstream scientific computing.
</p>

<p>
However, Julia is still very young, and still evolving rapidly. But if any of the above is true, I am <i>very</i> interested!
</p>

<p>
So, over the last few days, I re-implemented an algorithm in Julia. The previous version of the algorithm was written in Python. The algorithm spends most of it's time in FFTs, thus I didn't expect big performance gains.
</p>

<p>
It is actually nice to have a language that is built for scientific computation. Coming from Python, it is refreshing to have <a href="http://docs.julialang.org/en/release-0.3/manual/arrays/">array literals</a>, ranges and <a href="http://docs.julialang.org/en/release-0.3/stdlib/math/">mathematics</a> available without importing anything. Much like Python, Julia also has a proper <a href="http://docs.julialang.org/en/release-0.3/manual/modules/">module system</a>, comprehensions, and more than one function per file.
</p>

<p>
On the other hand, there are a few questionable design decisions as well. Julia uses 1-based, inclusive indexing (<code>range[1:3] = [1 2 3]</code> as opposed to Python's <code>range[:3] = [0, 1, 2]</code>). In practice, my experience is that I rarely need to add ±1 when indexing in Python, but I frequently need it in Julia/Matlab.
</p>

<p>
Also, Julia has no docstrings, which makes me sad. The whole documentation story is sad, really: Documentation is often incomplete, or missing altogether. Unit testing is not widespread at all, and still crude. 0.4 will apparently add docstrings <a href="https://github.com/MichaelHatherly/Docile.jl">using macros</a>. This is ugly and doesn't work for one's own code, but it's certainly a step in the right direction. Those error messages would need some work, too.
</p>

<p>
All of that is hopefully just a symptom of Julia being young, and will improve over time. Similarly, signal processing functions are missing entirely, and I had to re-implement some. The community is growing rapidly, though, and a lot of missing functionality can be installed through the <a href="http://docs.julialang.org/en/release-0.3/manual/packages/">package manager</a> already.
</p>

<p>
When it comes to writing code, there is a lot to like about Julia. Julia's type system does impose a bit of overhead, but it also grants immediate benefits: Many of Python's runtime errors happen at evaluation time and functions can easily document their arguments' types. Also, thinking strictly about types actually improved performance by a good 20% in my algorithm.
</p>

<p>
And finally, Performance is surprisingly good! Although my algorithm spends almost all of its time doing FFTs, Julia performed about twice as fast as Python. This is pretty much exactly twice as much as I had expected! It also exposed more of the <a href="http://docs.julialang.org/en/release-0.3/stdlib/math/?highlight=plan_fft#Base.plan_fft">features</a> of the underlying libraries, which could be used for another speed-up of some 10%.
</p>

<p>
At the end of the day, Julia clearly isn't mature yet, but very promising. Documentation and libraries will no doubt grow, and performance is already excellent. I'll definitely keep an eye on it, and will experiment further when the opportunity presents itself.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <link>https://bastibe.de/2015-01-12-julia.html</link>
  <guid>https://bastibe.de/2015-01-12-julia.html</guid>
  <pubDate>Mon, 12 Jan 2015 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[The 31. Chaos Communication Congress]]></title>
  <description><![CDATA[
<p>
Every year, between Christmas and New Year's Eve, a very special convention is held: The Chaos Computer Club hosts the Chaos Communication Congress. Among my peers, this is just "The Congress", the real highlight at the end of our year.
</p>

<p>
Don't be fooled by the name though, The Congress is not just some conference, with talks and meetings and business cards. The Congress is where every internet citizen, technologist, hacker, DIYer, net-politician, programmer, computer scientist, or geek convenes to exchange ideas. It is a place of levity, amazement and enlightening.
</p>


<figure id="orge8a1b01">
<img src="http://bastibe.de/static/2014-12/CCH.jpg" alt="CCH.jpg">

</figure>

<p>
The Congress lasts four days, and every day is packed full of exciting talks. My favorites:
</p>
<ul class="org-ul">
<li><a href="http://31c3.mirror.speedpartner.de/congress/2014/h264-hd/31c3-6450-de-en-Ich_sehe_also_bin_ich_Du_hd.mp4">Ich sehe, also bin ich … Du</a> (German)
As it turns out, you don't need special hardware to defeat defeat biometric scanners or passwords. A digital camera and some ingenuity is often enough.</li>
<li><a href="http://31c3.mirror.speedpartner.de/congress/2014/h264-hd/31c3-6573-en-de-From_Computation_to_Consciousness_hd.mp4">From Computation to Consciousness</a> (English)
This really resonated with me: What is consciousness? (Why) are animals or computers conscious or not? What does it all mean? Really, this is a computationally motivated introduction to constructivism. Highly recommended.</li>
<li><a href="http://31c3.mirror.speedpartner.de/congress/2014/h264-hd/31c3-6558-de-en-Traue_keinem_Scan_den_du_nicht_selbst_gefaelscht_hast_hd.mp4">Traue keinem Scan, den du nicht selbst gefälscht hast</a> (German)
The story of an entertaining person discovering that a scanned PDF does not necessarily contain the same text that was scanned if your scanner was built by Xerox.</li>
</ul>
<p>
All of these talks and <i>many</i> more are also <a href="http://31c3.mirror.speedpartner.de/congress/2014/h264-hd/">available online</a>, and I highly recommend you watch some of them. But The Congress is not just talks; this is where all the German hackspaces and user groups meet and present their projects. Walking through the halls, there are laser shows, quadrocopters, 3D printers, stitching machines, automatic cocktail mixers, mechanical and human musicians, and so much more.
</p>


<figure id="orgacfd61e">
<img src="http://bastibe.de/static/2014-12/hand.jpg" alt="hand.jpg">

</figure>

<p>
At its core though, this is a place where a bunch of like-minded people meet and take over a convention center. The Congress happens in the CCH, the Hamburg Convention Center. Over the course of the four days of The Congress, this building transforms from a sterile business location to a colorful geek-party. Within a day, all the lights in the building are somehow turned colorful, a pneumatic tube network sends messages across the building, there are lounges and coffee rooms, and strange and beautiful sculptures of light and electronics show up all over the place. Just walking across this cornucopia of light and sound is a treat for the senses.
</p>

<p>
And this is just the natural thing that happens if you let a bunch of creative people do their thing. It is really a crowd like no other: Nowhere else have I seen such an open-minded and approachable crowd. There are no unpleasant drunk people, no fights, no harassment. All over the place, people talk to strangers, adults and children build things together, and men and women interact as equals.
</p>

<p>
The Congress is really unique. I can't recommend it enough. If you can free up those four days between Christmas and New Year's Eve at all, go there. You won't regret it!
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-event.html">event</a> ]]></description>
  <category><![CDATA[event]]></category>
  <link>https://bastibe.de/2015-01-01-31c3.html</link>
  <guid>https://bastibe.de/2015-01-01-31c3.html</guid>
  <pubDate>Thu, 01 Jan 2015 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Books of 2014]]></title>
  <description><![CDATA[

<div id="outline-container-orgf11e272" class="outline-2">
<h2 id="orgf11e272"><a href="http://www.amazon.de/Ancillary-Justice-Imperial-Radch-English-ebook/dp/B00BU1DG1S/ref=sr_1_1?s=books-intl-de&amp;ie=UTF8&amp;qid=1419948379&amp;sr=1-1&amp;keywords=ancillary+justice">Ancillary Justice</a> / <a href="http://www.amazon.de/Ancillary-Sword-Imperial-Radch-English-ebook/dp/B00IA2E5VA/ref=sr_1_2?s=books-intl-de&amp;ie=UTF8&amp;qid=1419948379&amp;sr=1-2&amp;keywords=ancillary+justice">Ancillary Sword</a>, by Ann Leckie</h2>
<div class="outline-text-2" id="text-orgf11e272">
<p style="float:left;margin:5px;" width="150px">
<img src="https://upload.wikimedia.org/wikipedia/en/6/6a/Ann_Leckie_-_Ancillary_Justice.jpeg" alt="Ann_Leckie_-_Ancillary_Justice.jpeg" style="float:left;margin:5px;" width="150px">
I have been reading a lot of science fiction in the last few years. These books are part one and two of the best space opera I have ever read. The story is written from the perspective of an AI, sometimes inhabiting a lot of bodies, sometimes only one. Interestingly, this makes for a very introspective viewpoint, where politics and actions are expressed as consequences of nuanced human behavior and astute observation, as opposed to arbitrary human decisions. This perspective is extremely compelling, and makes for an extremely <i>human</i> story in a world that is a clever amalgamation of ancient Roman society and post-modern egalitarianism. There is no book I look forward to more fiercely than the conclusion of this series.
</p>
</div>
</div>

<div id="outline-container-org72e93a3" class="outline-2">
<h2 id="org72e93a3"><a href="https://en.wikipedia.org/wiki/Scott_Pilgrim">Scott Pilgrim</a>, by Bryan Lee O'Malley</h2>
<div class="outline-text-2" id="text-org72e93a3">
<p style="float:left;margin:5px;" width="150px">
<img src="https://upload.wikimedia.org/wikipedia/en/3/39/ScottPilgrim.jpg" alt="ScottPilgrim.jpg" style="float:left;margin:5px;" width="150px">
Scott Pilgrim is a twenty-something in the nineties. Scott Pilgrim doesn't have a job, and likes to play video games. Scott Pilgrim is fighting epic Anime battles against his girlfriends' exes. Scott Pilgrim is everyone, living in the real world. Scott Pilgrim is awesome, especially the new color-versions. The last part of the series will be released next year, and I really can't wait! (There's also a movie that is supposedly very good, but I won't watch it until I read all the comic books).
</p>

<br><br>
</div>
</div>

<div id="outline-container-org48ad78e" class="outline-2">
<h2 id="org48ad78e"><a href="http://www.amazon.de/Doomsday-Book-Connie-Willis/dp/0553562738/ref=sr_1_sc_2?ie=UTF8&amp;qid=1419948450&amp;sr=8-2-spell&amp;keywords=doomsday+boo">Doomsday Book</a>, by Connie Willis</h2>
<div class="outline-text-2" id="text-org48ad78e">
<p style="float:left;margin:5px;" width="150px">
<img src="https://upload.wikimedia.org/wikipedia/en/1/19/DoomsdayBook%281stEd%29.jpg" alt="DoomsdayBook%281stEd%29.jpg" style="float:left;margin:5px;" width="150px">
This is about time travel from near-future Britain to the fifteenth century. But then, an epidemic breaks loose: Britain is in quarantine and civil order starts breaking. At the same time in the fifteenth century, the plague hits. Disease, and the people trying to deal with it, is a human tragedy beyond belief. Connie Willis manages to write about these things with empathy, and astounding humane love and humor. This story moved me more deeply than I care to acknowledge.
</p>

<br><br><br>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-books.html">books</a> ]]></description>
  <category><![CDATA[books]]></category>
  <link>https://bastibe.de/2014-12-30-books-of-2014.html</link>
  <guid>https://bastibe.de/2014-12-30-books-of-2014.html</guid>
  <pubDate>Tue, 30 Dec 2014 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[A Digital Thank You]]></title>
  <description><![CDATA[
<p>
This is the time of the year when we reflect on our lives, and be thankful. We write Christmas cards to people we like, and celebrate with our loved ones. At my job, I am sitting in front of a screen all day, and I interacted not only with people, but also their software. So this is a column where I want to thank people I don't know for their delightful software:
</p>

<div id="outline-container-org5c4bab4" class="outline-2">
<h2 id="org5c4bab4"><a href="http://orgmode.org/">Org Mode</a></h2>
<div class="outline-text-2" id="text-org5c4bab4">
<p>
Thank you, Carsten Dominik, Bastien Guerry, and <a href="http://orgmode.org/org.html#History-and-Acknowledgments">everyone else</a>, for this amazing piece of software! I have used Org mode for my <a href="https://github.com/bastibe/org-journal">research journal</a>, <a href="http://bastibe.de/2013-11-13-blogging-with-emacs.html">this blog</a>, <a href="http://bastibe.de/2014-11-19-writing-a-thesis-in-org-mode.html">writing my thesis</a>, general note-taking, and all-around planning tool. Thank you for making my life so much easier to manage!
</p>
</div>
</div>

<div id="outline-container-org80e3ad6" class="outline-2">
<h2 id="org80e3ad6"><a href="https://github.com/mgeier">Matthias Geier</a></h2>
<div class="outline-text-2" id="text-org80e3ad6">
<p>
Thank you, Matthias, for your many contributions to <a href="https://github.com/bastibe/PySoundFile">PySoundFile</a> and <a href="https://github.com/bastibe/PySoundCard">PySoundCard</a>, and our many enlightening discussions. You have brought these two projects far further than I would have ever gone, and I learned a lot in the process! Also, a quick thank you to Github, which made our collaboration effortless and enjoyable.
</p>
</div>
</div>

<div id="outline-container-orge174ef6" class="outline-2">
<h2 id="orge174ef6"><a href="http://fishshell.com/">fish</a></h2>
<div class="outline-text-2" id="text-orge174ef6">
<p>
Thank you, <a href="http://ridiculousfish.com/">Ridiculous Fish</a>, for bringing sane scripting, glorious VGA color, and general awesomeness to the command line! Finally, a shell that does not drown you in messy configuration, crazy syntax, and archaic conventions. Finally, a shell with beautiful documentation, and sane defaults! Thanks for all the fish!
</p>
</div>
</div>

<div id="outline-container-orgf9ae5f1" class="outline-2">
<h2 id="orgf9ae5f1"><a href="http://www.getsync.com/">BitTorrent Sync</a></h2>
<div class="outline-text-2" id="text-orgf9ae5f1">
<p>
Dropbox is awesome, no doubt, but it still feels awkward to upload all my documents to a faceless corporation. Synchronizing data between computers is still hard&#x2013;or rather, used to be hard. Because this year I discovered btsync. I now have a real off-site backup and file synchronization system fully under my own control, and it took all of ten minutes to set up. Thank you!
</p>
</div>
</div>

<div id="outline-container-orgf7c2e29" class="outline-2">
<h2 id="orgf7c2e29"><a href="http://x-plane.com">X-Plane</a></h2>
<div class="outline-text-2" id="text-orgf7c2e29">
<p>
This year, I got back into an old hobby of mine: Flight Simulation. In particular, this year I re-discovered X-Plane, and the marvelous and free sceneries by <a href="http://simheaven.org/">SimHeaven</a> and <a href="http://www.alpilotx.net/">Andras Fabian</a>. Sadly, there doesn't seem to be any pilot school around where I can complete my real-world pilot's license, so flight simulation will have to do. But with this simulator, I am enjoying flight simulation more than ever!
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-thank-you.html">thank-you</a> ]]></description>
  <category><![CDATA[thank-you]]></category>
  <link>https://bastibe.de/2014-12-20-thanks.html</link>
  <guid>https://bastibe.de/2014-12-20-thanks.html</guid>
  <pubDate>Sat, 20 Dec 2014 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Choosing a German Email Provider]]></title>
  <description><![CDATA[
<p>
Why not just use Gmail<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>? Because if you're not paying for the service, you <i>are</i> the service. Google gives you Gmail for free, and in return they analyze and market your data. That's a fair deal, as far as I am concerned. But not a deal I want to make.
</p>

<p>
For one thing, I just don't like the idea of someone else reading through my email. Furthermore, I'd like my emails to be hosted in the same country I live in<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup>, so that all the laws that protect the privacy of my letters are just as valid for my emails. So a German email provider it is.
</p>

<p>
First, I tried <a href="http://mail.de">mail.de</a>. They show ads, even if you pay them. Also, their web interface is surprisingly ugly. No thank you.
</p>

<p>
Then, I found <a href="http://posteo.de">posteo.de</a>, and they seemed to be doing everything right! Hosted in Germany, a buck a month, with a focus on security and privacy, and seemingly developed by friendly people. They even try to be environmentally friendly. In summary: perfect!
</p>

<p>
After half a year of using Posteo, though, I have found a few niggles. The web interface can't search mailboxes with a lot of emails&#x2013;I have an archive directory with 14k emails and the search wouldn't work. Their support says that's because there are too many messages in that directory. Also, they have had a bit too much down time for my taste: I experienced three outages of about two hours each in the last half year. Not a deal breaker, but it doesn't exactly instill confidence in their infrastructure.
</p>

<p>
Enter <a href="http://mailbox.org">mailbox.org</a>. Also German, also a buck a month, also friendly and safe and eco-conscious. But with a much nicer web interface, support for custom domains, and a working search box. They even support ActiveSync, which you'll like if you use Outlook or Windows Phone. In other words, Posteo done right. I'm sold.
</p>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
Or <a href="http://outlook.com">outlook.com</a>, which is the same deal from Microsoft. Use this if you don't like Google's "priority" inbox and wonky IMAP support.
</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
For the record, <a href="http://arstechnica.com/tech-policy/2014/09/judge-mulls-contempt-charges-in-microsofts-e-mail-privacy-fight-with-us/">Microsoft</a> has made a point of having servers in each user's country and abiding by that country's law.
</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-computers.html">computers</a> ]]></description>
  <category><![CDATA[computers]]></category>
  <link>https://bastibe.de/2014-12-09-mailbox.html</link>
  <guid>https://bastibe.de/2014-12-09-mailbox.html</guid>
  <pubDate>Tue, 09 Dec 2014 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Org Mode Selective Section Numbering]]></title>
  <description><![CDATA[
<p>
This is the third revision of a post about selective headline numbering in Org mode. On its own, Org mode can either number all headlines, or none. For scientific writing, this is a non-starter. In a scientific paper, the abstract should not be numbered, the main body should be numbered, and appendices should not be numbered.
</p>

<p>
In LaTeX, this is easy to do: <code>\section{}</code> creates a numbered headline, while <code>\section*{}</code> creates an unnumbered section. Org mode does not have any facility to control this on a per-headline basis, but it can be taught:
</p>

<div class="org-src-container">
<pre class="src src-elisp">(defun headline-numbering-filter (data backend info)
  "No numbering in headlines that have a property :numbers: no"
  (let* ((beg (next-property-change 0 data))
         (headline (if beg (get-text-property beg :parent data))))
    (if (and (eq backend 'latex)
         (string= (org-element-property :NUMBERS headline) "no"))
        (replace-regexp-in-string
         "\\(part\\|chapter\\|\\(?:sub\\)*section\\|\\(?:sub\\)?paragraph\\)"
         "\\1*" data nil nil 1)
      data)))

(setq org-export-filter-headline-functions '(headline-numbering-filter))
</pre>
</div>

<p>
This creates a filter (an Org mode convention similar to a hook), which appends the asterisk to LaTeX headlines if the headline has a property <code>:NUMBERS: no</code>. If all you do is export to LaTeX, this works well.
</p>

<p>
If you need to export to HTML as well, things get more complicated. Since HTML does not have native numbering support, Org is forced to manually create section numbers. But times have changed, and with CSS3, HTML now indeed <i>does</i> support native numbering!
</p>

<p>
Here is some CSS that uses CSS3 counters to number all headlines and hide Org's numbers:
</p>

<div class="org-src-container">
<pre class="src src-css">/* hide Org-mode's section numbers */
span.section-number-2 { display: none; }
span.section-number-3 { display: none; }
span.section-number-4 { display: none; }
span.section-number-5 { display: none; }
span.section-number-6 { display: none; }

/* define counters for the different headline levels */
h1 { counter-reset: section; }
h2 { counter-reset: subsection; }
h3 { counter-reset: subsubsection; }
h4 { counter-reset: paragraph; }
h5 { counter-reset: subparagraph; }

/* prepend section numbers before headlines */
h2::before {
    content: counter(section) " ";
    counter-increment: section;
}
h3::before {
    content: counter(section) "." counter(subsection) " ";
    counter-increment: subsection;
}
h4::before {
    content: counter(section) "." counter(subsection) "." counter(subsubsection) " ";
    counter-increment: subsubsection;
}
h5::before {
    content: counter(section) "." counter(subsection) "." counter(subsubsection) "." counter(paragraph) " ";
    counter-increment: paragraph;
}
h6::before {
    content: counter(section) "." counter(subsection) "." counter(subsubsection) "." counter(paragraph) "." counter(subparagraph) " ";
    counter-increment: subparagraph;
}

/* suppress numbering for headlines with class="nonumber" */
.nonumber::before { content: none; }
</pre>
</div>

<p>
With this in place, we can extend the previous filter to work for HTML as well as LaTeX:
</p>

<div class="org-src-container">
<pre class="src src-elisp">(defun headline-numbering-filter (data backend info)
  "No numbering in headlines that have a property :numbers: no"
  (let* ((beg (next-property-change 0 data))
         (headline (if beg (get-text-property beg :parent data))))
    (if (string= (org-element-property :NUMBERS headline) "no")
        (cond ((eq backend 'latex)
               (replace-regexp-in-string
                "\\(part\\|chapter\\|\\(?:sub\\)*section\\|\\(?:sub\\)?paragraph\\)"
                "\\1*" data nil nil 1))
              ((eq backend 'html)
               (replace-regexp-in-string
                "\\(&lt;h[1-6]\\)\\([^&gt;]*&gt;\\)"
                "\\1 class=\"nonumber\"\\2" data nil nil)))
      data)))

(setq org-export-filter-headline-functions '(headline-numbering-filter))
</pre>
</div>

<p>
Previously, I implemented this in Org mode only (no CSS). While that worked as well, it required the modification of some fairly low-level Org functions. The CSS-based solution is much simpler, and should be much easier to maintain and adapt.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-org-mode.html">org-mode</a> <a href="https://bastibe.de/tag-emacs.html">emacs</a> ]]></description>
  <category><![CDATA[org-mode]]></category>
  <category><![CDATA[emacs]]></category>
  <link>https://bastibe.de/2014-12-03-org-numbering.html</link>
  <guid>https://bastibe.de/2014-12-03-org-numbering.html</guid>
  <pubDate>Wed, 03 Dec 2014 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Writing a Thesis in Org Mode]]></title>
  <description><![CDATA[
<p>
Most of my peers write all their scientific documents in LaTeX. Being a true believer in the power of Emacs, I opted for writing my master's thesis in <a href="http://orgmode.org/">Org Mode</a> instead. Here's my thoughts on this process and how it compares to the usual LaTeX work flow.
</p>

<p>
In my area of study, a thesis is a document of about 60 pages that contains numerous figures, math, citations, and the occasional table or source code snippet. Figures are usually graphs that are generated in some programming environment and creating those graphis is a substantial part of writing the thesis.
</p>

<p>
Org mode was a huge help in this regard, since it combines the document text and the executable pieces of code. Instead of having a bunch of scripts that generate graphs, and a bunch of LaTeX files that include those graphs, I had one big Org file that included both the thesis text and the graphing code.
</p>

<p>
As for the thesis text, I used Org's export functionality to convert the Org source to LaTeX, and compiled a PDF from there. This really works very well: It is very nice to use Org headlines instead of <code>\section{...}</code>, and clickable Org links instead of <code>\ref{...}</code>. While this is nice, it is just a change of syntax. I still had to enter the very same things and saving a few characters is not particularly impressive. For example, figures still require a caption, an ID, and a size:
</p>

<div class="org-src-container">
<pre class="src src-org">#+CAPTION: Modulation tracks of a clarinet recording with and without white noise. The modulation tracks are not normalized.
#+ATTR_LATEX: :width 6in :height 2.5in :float multicolumn
#+NAME: fig:summary_tracks
[[file:images/summary_tracks.pdf]]
</pre>
</div>

<p>
In LaTeX, this would be
</p>

<div class="org-src-container">
<pre class="src src-latex">\begin{figure*}
\centering
\includegraphics[width=6in,height=2.5in]{images/summary_tracks.pdf}
\caption{\label{fig:summary_tracks}Modulation tracks of a clarinet recording with and without white noise. The modulation tracks are not normalized.}
\end{figure*}
</pre>
</div>

<p>
As you can see, there really is not that much of a difference between these two, and you might even consider the LaTeX example more readable. In some other areas, Org mode is simply lacking features: Org does not have any syntax for page formatting, and thus can't create a perfectly formatted title page. Similarly, it can't do un-numbered sections, and it can't do numbered equations. For all of those, I had to fall back to writing LaTeX. This is not a big deal, but it breaks the abstraction.
</p>

<p>
A bigger problem is that Org documents include all the chapters in one big file. While Org can deal with large files no problem, it means that LaTeX compiles take a while. In LaTeX, I would have split my document into a number of smaller files that could be separately compiled in order to keep compilation time down. This is confounded by Org's default behavior of deleting intermediate LaTeX files, which forces a full triple-recompile on each export. At the end of my thesis, a full export took about 15 seconds. Not a deal-breaker, but annoying.
</p>

<p>
The one thing where Org really shines, though, is the inclusion of code fragments: Most of my figures were created in Python, and Org mode allowed me to include that Python code right in my document. Hit <code>C-c C-c</code> on any code fragment, and Org ran that code and created a new image file that is automatically included as a figure. This was really tremendously useful!
</p>

<p>
At the end of the day, I am not sure whether Org mode is the right tool for writing a thesis. It worked fine, but there were a lot of edge cases and <a href="http://bastibe.de/2014-09-23-org-cite.html">workarounds</a>, which made the whole process a bit uncomfortable. The only really strong argument in favor of Org is the way it can include both code and prose in the same document. But maybe a similar thing could be implemented with LaTeX and some literate programming tool.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-org-mode.html">org-mode</a> <a href="https://bastibe.de/tag-emacs.html">emacs</a> ]]></description>
  <category><![CDATA[org-mode]]></category>
  <category><![CDATA[emacs]]></category>
  <link>https://bastibe.de/2014-11-19-writing-a-thesis-in-org-mode.html</link>
  <guid>https://bastibe.de/2014-11-19-writing-a-thesis-in-org-mode.html</guid>
  <pubDate>Wed, 19 Nov 2014 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Org Mode Citation Links]]></title>
  <description><![CDATA[
<p>
I am writing my master's thesis in <a href="http://orgmode.org/">Org Mode</a>, and export to LaTeX for publishing. For the most part, this works incredibly well. Using Org Mode instead of plain LaTeX means no more fiddly <code>\backslash{curly brace}</code> all over the place. No more scattering code fragments and markup across hundreds of files. And on top of that, deep integration with my research notes and task tracking system.
</p>

<p>
But not everything is perfect. For one thing, citations do not work well. Sure, you can always write <code>\cite{cohen93}</code>, but then you are writing LaTeX again. Also, all the other references and footnotes are clickable, highlighted Org Mode links, but <code>\cite{cohen93}</code> is just inline LaTeX.
</p>

<p>
But luckily, this is Emacs, and Emacs is programmable. And better yet, Org Mode has just the tool for the job:
</p>

<div class="org-src-container">
<pre class="src src-elisp">(org-add-link-type "cite"
     (defun follow-cite (name)
       "Open bibliography and jump to appropriate entry.
        The document must contain \bibliography{filename} somewhere
        for this to work"
       (find-file-other-window
        (save-excursion
          (beginning-of-buffer)
          (save-match-data
            (re-search-forward "\\\\bibliography{\\([^}]+\\)}")
            (concat (match-string 1) ".bib"))))
       (beginning-of-buffer)
       (search-forward name))
     (defun export-cite (path desc format)
       "Export [[cite:cohen93]] as \cite{cohen93} in LaTeX."
       (if (eq format 'latex)
           (if (or (not desc) (equal 0 (search "cite:" desc)))
               (format "\\cite{%s}" path)
             (format "\\cite[%s]{%s}" desc path)))))
</pre>
</div>

<p>
This registers a new link type in Org Mode: <code>[[cite:cohen93]]</code>, which will jump to the appropriate bibliography entry when clicked, and get exported as <code>\cite{cohen93}</code> in LaTeX. Awesome!
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-org-mode.html">org-mode</a> <a href="https://bastibe.de/tag-emacs.html">emacs</a> ]]></description>
  <category><![CDATA[org-mode]]></category>
  <category><![CDATA[emacs]]></category>
  <link>https://bastibe.de/2014-09-23-org-cite.html</link>
  <guid>https://bastibe.de/2014-09-23-org-cite.html</guid>
  <pubDate>Tue, 23 Sep 2014 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Transplant]]></title>
  <description><![CDATA[
<p>
In academia, a lot of programming is done in Matlab. Many very interesting algorithms are only available in Matlab. Personally, I prefer to use tools that are more widely applicable, and less proprietary, than Matlab. My weapon of choice at the moment is Python.
</p>

<p>
But I still need to use Matlab code. There are <a href="http://stackoverflow.com/a/23762412/1034">a few ways</a> of interacting with Matlab out there already. Most of them focus on being able to eval strings in Matlab. Boring. The most interesting one is <a href="https://github.com/ewiger/mlab">mlab</a>, a full-fledget bridge between Python and Matlab! Had I found this earlier, I would probably not have written my own.
</p>

<p>
But write my own I did: <a href="https://github.com/bastibe/transplant">Transplant</a>. Transplant is a very simple bridge for calling Matlab functions from Python. Here is how you start Matlab from Python:
</p>

<div class="org-src-container">
<pre class="src src-python">import transplant
matlab = transplant.Matlab()
</pre>
</div>

<p>
This <code>matlab</code> object starts a Matlab interpreter in the background and connects to it. You can call Matlab functions on it!
</p>

<div class="org-src-container">
<pre class="src src-python">matlab.eye(3)
&gt;&gt;&gt; array([[ 1.,  0.,  0.],
           [ 0.,  1.,  0.],
           [ 0.,  0.,  1.]])
</pre>
</div>

<p>
As you can see, Matlab matrices are converted to Numpy matrices. In contrast to most other Python/Matlab bridges, matrix types are preserved<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>:
</p>

<div class="org-src-container">
<pre class="src src-python">matlab.randi(255, 1, 4, 'uint8')
&gt;&gt;&gt; array([[246,    2, 198, 209]], dtype=uint8)
</pre>
</div>

<p>
All matrix data is actually transferred in binary, so both Matlab and Python work on bit-identical data. This is very important if you are working with precise data! Most other bridges do some amount of type conversion at this point.
</p>

<p>
This alone accounts for a large percentage of Matlab code out there. But not every Matlab function can be called this easily from Python: Matlab functions behave differently depending the number of output arguments! To emulate this in Python, every function has a keyword argument <code>nargout</code> <sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup>. For example, the Matlab function <code>max</code> by default returns both the maximum value and the index of that value. If given <code>nargout=1</code> it will only return the maximum value:
</p>

<div class="org-src-container">
<pre class="src src-python">data = matlab.randn(1, 4)
matlab.max(data)
&gt;&gt;&gt; [1.5326, 3] # Matlab: x, n = max(...)
matlab.max(data, nargout=1)
&gt;&gt;&gt; 1.5326      # Matlab: x = max(...)
</pre>
</div>

<p>
If no <code>nargout</code> is given, functions behave according to <code>nargout(@function)</code>. If even that fails, they return the content of <code>ans</code> after their execution.
</p>

<p>
Calling Matlab functions is the most important feature of Transplant. But there is a more:
</p>

<ul class="org-ul">
<li><p>
You can save/retrieve variables in the global workspace:
</p>

<div class="org-src-container">
<pre class="src src-python">  matlab.value = 5 # Matlab: value = 5
  x = matlab.value # Matlab: x = value
</pre>
</div></li>

<li><p>
You van eval some code:
</p>

<div class="org-src-container">
<pre class="src src-python">  matlab.eval('class(value)')
  &gt;&gt;&gt; ans =
  &gt;&gt;&gt;
  &gt;&gt;&gt; double
  &gt;&gt;&gt;
</pre>
</div></li>

<li>The help text for functions is automatically assigned as docstring. In IPython, this means that <code>matlab.magic?</code> displays the same thing <code>help magic</code> would display in Matlab.</li>
</ul>

<p>
Under the hood, Transplant is using a very simple messaging protocol based on <a href="http://zeromq.org/">0MQ</a>, <a href="https://en.wikipedia.org/wiki/Json">JSON</a>, and some <a href="https://en.wikipedia.org/wiki/Base64">base64</a>-encoded binary data. Sadly, Matlab can deal with none of these technologies by itself. Transplant therefore contains a full-featured JSON <a href="https://github.com/bastibe/transplant/blob/master/parsejson.m">parser</a>/<a href="https://github.com/bastibe/transplant/blob/master/dumpjson.m">serializer</a> and base64 <a href="https://github.com/bastibe/transplant/blob/master/base64encode.m">encoder</a>/<a href="https://github.com/bastibe/transplant/blob/master/base64decode.m">decoder</a> in pure Matlab. It also contains a minimal <a href="https://github.com/bastibe/transplant/blob/master/messenger.c">mex-file</a> for interfacing with 0MQ.
</p>

<p>
There are a few <a href="http://iso2mesh.sourceforge.net/cgi-bin/index.cgi?jsonlab">JSON parsers</a> available for Matlab, but virtually all of them try parse JSON arrays as matrices. This means that these parsers have no way of differentiating between a list of vectors and a matrix (want to call a function with three vectors or a matrix? No can do). Transplant's JSON parser parses JSON arrays as cell arrays and JSON objects as structs. While somewhat less convenient in general, this is a much better fit for transferring data structures between programming languages.
</p>

<p>
Similarly, there are a few <a href="http://home.online.no/~pjacklam/matlab/software/util/datautil/">base64 encoders</a> available. Most of them actually use Matlab's built-in Java interface to encode/decode base64 strings. I tried this, but it has two downsides: Firstly, it is pretty slow for short strings since the data has to be copied over to the Java side and then back. Secondly, it is limited by the Java heap space. I was not able to reliably encode/decode more than about 64 Mb using this<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup>. My base64 encoder/decoder is written in pure Matlab, and works for arbitrarily large data.
</p>

<p>
All of this has been about Matlab, but my actual goal is bigger: I want transplant to become a library for interacting between more than just Python and Matlab. In particular, Julia and PyPy would be very interesting targets. Also, it would be useful to reverse roles and call Python from Matlab as well! But that will be in the future.
</p>

<p>
For now, head over to <a href="https://github.com/bastibe/transplant">Github.com/bastibe/transplant</a> and have fun! Also, if you find any bugs or have any suggestions, please open an issue on Github!
</p>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
Except for integer complex numbers, since those are not supported by Numpy.
</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
Like the Matlab function <code>nargout</code>
</p></div></div>

<div class="footdef"><sup><a id="fn.3" class="footnum" href="#fnr.3" role="doc-backlink">3</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
At 192 Mb of Java heap space. And even those 64 Mb were pretty unreliable if I didn't call <code>java.lang.Runtime.getRuntime.gc</code> all the time.
</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-python.html">python</a> <a href="https://bastibe.de/tag-matlab.html">matlab</a> ]]></description>
  <category><![CDATA[python]]></category>
  <category><![CDATA[matlab]]></category>
  <link>https://bastibe.de/2014-08-19-transplant.html</link>
  <guid>https://bastibe.de/2014-08-19-transplant.html</guid>
  <pubDate>Tue, 19 Aug 2014 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Working and Learning]]></title>
  <description><![CDATA[
<p>
At the university, I have a big advantage: I can program. So many of my fellow students are programming as their main means of doing science, yet clearly never learned how to program efficiently. It is saddening to see them "fight Matlab" for days, for things that would take a programmer hours.
</p>

<p>
So how did I get to this point? After all, I went to the same university and studied the same topics they did. My first introduction to programming was our <i>Introduction to Programming</i> in the first semester. We learned how to write simple text-based programs in C.
</p>

<div id="outline-container-org1434b17" class="outline-2">
<h2 id="org1434b17">My own blogging engine</h2>
<div class="outline-text-2" id="text-org1434b17">
<p>
At the time, my fellow students and I wanted to organize our lecture notes, copied exams, and assignments on our own website. Not knowing any better, I picked up PHP and set out to write a little website for this. It turned into a little CMS, all hand-written in PHP, HTML and (almost no) CSS.
</p>

<p>
This happened about four weeks into the introductory programming course, so I only knew a few bits of C and didn't appreciate the differences between programming languages yet. Many bad things have been said about PHP, but it allowed me to hack together a blog, file browser, gallery, and calendar with knowing little more about programming than branches and loops.
</p>

<p>
It scares me to look at the ease with which I picked up PHP at the time. With more experience, I seem to become more reluctant to try out new things. This might be a very bad thing.
</p>
</div>
</div>

<div id="outline-container-org864ea37" class="outline-2">
<h2 id="org864ea37">C programming at the university</h2>
<div class="outline-text-2" id="text-org864ea37">
<p>
In my third semester, a professor offered me a job as an undergraduate research assistant. As my first assignment, he wanted me to program a MIDI interface for Matlab. The idea was to use the Matlab-C interface <a href="http://www.mathworks.de/de/help/matlab/call-mex-files-1.html">Mex</a> to connect <a href="http://portmedia.sourceforge.net/">portmidi</a> to Matlab. At this point, I had had two programming courses (C and C++/Matlab), and had read <a href="http://pragprog.com/book/tpp/the-pragmatic-programmer"><i>The Pragmatic Programmer</i></a>.
</p>

<p>
I remember the professor telling me to stop obsessing about that piece of code. He said "You are an engineer, 95% is good enough for engineers". Yet, reading through this code now, it is <a href="http://tgm.jade-hs.de/web/files/Institut_fr_Hrtechnik_und_Audiologie/Software.php">some fine C code</a>. Everything is well-commented, the implementation is clearly split into one Matlab-related part and one portmidi-related part, and there even is an (informal) test suite! To my mind, those extra 5% make an incredible difference! It is astonishing how much my early career has been influenced by <i>The Pragmatic Programmer</i>.
</p>

<p>
Another project concerned extending a C program that simulated small-room acoustics. It took me eight months to admit defeat. Every week, I would spend ten hours staring at my screen, trying to understand that program. Every week, I would fail in frustration. After eight months, I told the professor that I couldn't do it. A few months later, I told the professor that I would have another go at the project. This time, I read <a href="http://www.trueaudio.com/array/downloads/Image%20Method-Allen%20and%20Berkley%201978.pdf">the research paper</a> associated with the program first. After that, the project was completed in one afternoon. Sometimes, just reading the code is not enough. (This is probably more true in academia than anywhere else).
</p>
</div>
</div>

<div id="outline-container-orgf436f97" class="outline-2">
<h2 id="orgf436f97">Qt and Cocoa and OpenGL</h2>
<div class="outline-text-2" id="text-orgf436f97">
<p>
I wrote my bachelor's thesis for a small company in southern Germany. At my university, the thesis was supposed to take half a year, and should be written at some company, so students would get some first-hand experience of the real world outside the university.
</p>

<p>
The basic algorithm for the thesis was working after a few weeks. Since my boss was more interested in a commercial result than in more research, he proposed that I write a desktop application for it. This is how I was introduced to Qt. Qt is an incredibly complex framework. Luckily for me, it is also an incredibly well-documented framework! As a newcomer to programming, API docs can be a very daunting thing, filled with jargon and implementation detail. This was the first time I learned something mostly from reading the API docs, and I am grateful that I happened to pick Qt for that.
</p>

<p>
After finishing my thesis, I worked remotely for the same company, writing another GUI application. This time, the program was to be written in Objective-C/Cocoa. In contrast to Qt, I needed <a href="http://www.bignerdranch.com/we-write/cocoa-programming">the book</a> to learn Cocoa. Working through the book was a very different experience than learning Qt from API docs. The book not only described the API, but also things like best practices and programming patterns. As a result, my final program was much easier to understand and extend than the Qt program I wrote earlier.
</p>

<p>
Cocoa and Qt show two very different styles of documentation. The Qt documentation is very complete, and very well-written. It is a rare feat for a framework this complex to be learnable from the documentation alone! Doing the same thing with the Cocoa documentation instead of the book would have been painful. The book really went much further than pure API documentation can reasonably go, and my experience was better for it! (By the way, I also learned and used OpenGL during that time. The less said about the OpenGL documentation, the better).
</p>
</div>
</div>

<div id="outline-container-org66cfa16" class="outline-2">
<h2 id="org66cfa16">Why Software is paid for</h2>
<div class="outline-text-2" id="text-org66cfa16">
<p>
In the meantime, the company had been bought by a foreign investor. While this meant that my program would never see actual users, it also meant that they could offer me a proper job. And like every good engineering student, I needed Matlab, Photoshop, and Microsoft Office. And like every cliché foreign investor, they replied with "This is too expensive, here is a link to the Pirate Bay".
</p>

<p>
This did not sit well with me. After a bit of soul-searching, and my most interesting and obviously <a href="http://stackoverflow.com/questions/3907076/my-boss-asks-me-to-pirate-software-what-should-i-do">soon-deleted Stack Overflow question</a>, I realized that I could not pirate software any longer. My own livelihood depended on people paying for the code I wrote. There was no way I would use other people's code without paying for it.
</p>

<p>
And thus we used <a href="http://www.inkscape.org/">Inkscape</a> instead of Illustrator, and <a href="http://scipy.org/">Python</a> instead of Matlab. Mere weeks later, I discovered that Inkscape produces (mostly) standard-compatible SVG files that could be opened with any regular text editor, and manipulated with any regular XML parser! It soon became apparent that the open nature of this file format enabled us to use Inkscape for so much more than mere vector graphics! While in retrospect, it was not such a bright idea to use a vector graphics program as a GUI layout editor, it really drove home the value of open file formats and reusability! A lot of the later work on the project would have been impossible had we used Illustrator and Matlab.
</p>
</div>
</div>

<div id="outline-container-orgfb19963" class="outline-2">
<h2 id="orgfb19963">Automation</h2>
<div class="outline-text-2" id="text-orgfb19963">
<p>
We were working with a British company on a new <a href="http://www.cadac-sound.com/i/digital/cdc-four/12/">digital mixing console</a> at the time. Our team was mostly responsible for the software side of the project, while the British company was mostly concerned with the hardware. One big issue was that in order to get a testable system going, one had to compile some software, run some converter scripts on some files, zip some other files, set up the prototype hardware correctly, then send all the files to the prototype in the right order. Forget one step, or take an outdated version of something, and the system would not work.
</p>

<p>
It was a disaster. We would lose days debugging nonexistent issues, only because we had forgotten to update such-and-such library, or renaming some debugging file. It would be easy to blame this on my colleagues. But the reality is, no-one had ever done a project this large before, and our tools were utterly incapable of build automation of this kind.
</p>

<p>
In the end, I wrote some crazy Rube Goldberg Machine that integrated GNU make with Visual Studio, and delegated all the packaging and converting to makefiles. It would even download a large set of Unix tools and a full installation of Ruby if need be. I can't say I'm proud of this wild contraption, but anything is better than wasting days debugging non-issues. To its credit, there have been zero issues with wrongly packaged files with this system in place. I can not tell you how much stress and conflict this simple act of automation relieved. Never have a human do a machine's work.
</p>
</div>
</div>

<div id="outline-container-org6404116" class="outline-2">
<h2 id="org6404116">Lua and DSLs</h2>
<div class="outline-text-2" id="text-org6404116">
<p>
When I started on the job, a colleague of mine handed me a copy of "Programming for Windows 95", and told me to read it since he had modeled the internal GUI library after it. This was 2010. I was very unhappy about this. In the following years, I would rework many a subsystem within this library. But the more I changed, the more I had to take responsibility for the library. Before long, I had taken official ownership of the library, and I had to answer to questions and feature requests.
</p>

<p>
This turned out to be both a blessing and a curse. On the one hand, it gave me a great deal of freedom and authority in my own little world. On the other hand, I didn't really care for responsibility for this much legacy code in an application domain I was not particularly interested in. Thus being motivated to change things had its upsides though, and I learned a lot when implementing a font rendering engine, a bitmap caching and memory allocation system, and various configuration mechanisms on an embedded platform.
</p>

<p>
But, at the end of the day, there is only so much you can do with a bad code base in a bad subset of C++ (largely due to compilers, not people). In another slow-going week when GUI work was not particularly important, I <a href="http://stackoverflow.com/questions/4448835/alternatives-to-lua-as-an-embedded-language">investigated implementing</a> a scripting layer for our framework. We were not very optimistic about this, since the scripting engine had to run on a <a href="https://en.wikipedia.org/wiki/Black_fin">terribly slow embedded processor</a> that was already running almost at capacity.
</p>

<p>
We chose the scripting language Lua for the job, since it was tiny, and easy to embed (in both meanings of the word). Lua turned out to be a stellar choice! As scripting systems often go, the Lua code took over most of the frontend work in the application. Before long, all the GUI layout was done in a Lua DSL instead of XML. Imagine creating 200 buttons in a two-line <code>for</code> loop instead of 200 lines of XML. Also, I consider the book <a href="http://www.lua.org/pil/">Programming in Lua</a> one of the pivotal books in my programming career!
</p>

<p>
All the GUI and hardware interaction was done in Lua. The mixing console had some 40000 parameters, and a terrifying number of hardware states. I daresay that it would have been all but impossible to implement the complex interplay between all of these states in a less dynamic environment than Lua. Years later, one of the later maintainers of the product told me how this system had saved his sanity many times. This was one of the proudest moments in my career!
</p>

<p>
I vividly remember the feeling of liberation when I transitioned from C++ to Lua. I don't think we would have managed to ship the mixing console in time without Lua. In fact, there was one feature from the old analogue mixing consoles that they never managed to implement in the newer digital consoles, because it was just too hard. With Lua, it was a giant headache, but it worked. Never underestimate the power of a different language when problems seem impossibly hard.
</p>
</div>
</div>

<div id="outline-container-org03f1f4a" class="outline-2">
<h2 id="org03f1f4a">The role of boredom in my job</h2>
<div class="outline-text-2" id="text-org03f1f4a">
<p>
The Lua experiment started in a time when work was slow, and idle thoughts had the time to mature into ideas. The system automation was started in a similar time. I was lucky to have had a few of those weeks. Some of them amounted to cool projects in the company, others I spent on improving myself.
</p>

<p>
I always had a bit of a fetish for text editing. I just love the act of feeding thoughts to the computer through a keyboard. To me, it is a much more satisfying experience than using a pencil and a sheet of paper. At the university, I used Vim on Linux, then Textmate on OS X, then XCode. On the job, I was then forced to use Visual Studio, which still holds a special place in my heart, as one of the most miserable editing experience I ever had (though Lotus Notes and Microsoft Word only rank lower because I used them less).
</p>

<p>
It should come as no surprise then, that I was overjoyed when I discovered <a href="http://www.viemu.com/">ViEmu</a>. It really transformed my work at the time &#x2013; what was previously a chore was now made enjoyable by the feeling of power conveyed through the Vim key bindings in Visual Studio! And this improved even further when I used another spare week to finally learn how to properly touch-type. These days, I am typing in Emacs, but enough has been written about that already.
</p>

<p>
I had one colleague who only used his two index fingers for typing. Seeing him type was maddening. But the worst thing was not his typing, but what he was <i>not</i> typing. Naturally, variable names were short, documentation was sparse, and code was optimized for brevity. He even resorted to some graphical code editing <a href="http://www.easycode.de/en/products/easycode-cc/structure-diagrams.html">monstrosity</a>, just to save himself some typing. I have written a Visual Studio tool that automatically filtered out some of the junk this tool produced, and wrote wrappers around his libraries to make them usable for other people. Seriously, don't be that guy. Typing is a core competency for any developer.
</p>
</div>
</div>

<div id="outline-container-org44a4325" class="outline-2">
<h2 id="org44a4325">Open Source</h2>
<div class="outline-text-2" id="text-org44a4325">
<p>
Besides all of the GUI work I did for the company, I was actually hired for audio algorithm development. Since we didn't get a license for Matlab, I quickly grew to love Python instead. At the time, Python was right in the middle of the transition from Python 2 to Python 3, and <a href="http://people.csail.mit.edu/hubert/pyaudio/">one of the libraries</a> I needed was Python 2 only. In another one of those fateful slow weeks, I set out to translate it to Python 3.
</p>

<p>
I didn't know much Python at the time, so the result was not exactly perfect. The maintainer of the library however was really nice about this, and helped me figuring out the problems with my code. This was the first time I ever talked to any programmer outside my company! And even better, this programmer seemed to be a professor at MIT, or something, and likely a lot more experienced and intelligent than I was! I was incredibly lucky that this first contact with the open source world was such a kind and positive one.
</p>

<p>
Not too long after that, I started writing my own <a href="https://github.com/bastibe/">open source libraries</a>, and publishing them on the web. And before too long, people began using those projects! And then they started contributing to them as well! In a way, one of my main griefs with working for a company has always been that there are so few people with which you can talk about the things you do all day. And now, suddenly, random people from all over the world are showing interest and help for the things I do in my spare time! I really can't emphasize enough how much this involvement with the open source community and other people has improved my view of the world, and my understanding of the work I do!
</p>
</div>
</div>

<div id="outline-container-orga9afd24" class="outline-2">
<h2 id="orga9afd24">My next adventure</h2>
<div class="outline-text-2" id="text-orga9afd24">
<p>
This has been a summary of the things I did so far. It has been an incredible journey, and one that never stopped to surprise me. Now I am finishing my master's thesis, and getting ready for a doctorate after that. All the work I did and do is based on the incredible work of people before me. At least for the time being, I want this to be the goal of my further work: To advance the sum total knowledge of the world, if only by a tiny bit.
</p>

<p>
For this, my most important tool is still programming. Learning how to program is an immensely valuable skill, and <a href="http://learnpythonthehardway.org/book/advice.html">doubly so</a> if your job title is not "developer" or "programmer". Programming is not just a tool to talk to the computer and earn a living. We should not forget that programming is also a rich thinking tool for trying out new ideas, and sharing them with other people.
</p>

<p>
For the moment, I have no desire for being beholden to some company dictating my goals and hiding my achievements. Writing this up has proven to be a very liberating and insightful experience for myself, just the way my <a href="https://github.com/bastibe/org-journal">research journal</a> is for my day-to-day work. Putting ideas and algorithms in writing is an incredibly useful tool for finding one's place in the world and contributing to its betterment!
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <link>https://bastibe.de/2014-07-20-working-and-learning.html</link>
  <guid>https://bastibe.de/2014-07-20-working-and-learning.html</guid>
  <pubDate>Sun, 20 Jul 2014 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Speeding Up Org Mode Publishing]]></title>
  <description><![CDATA[
<p>
I use <code>org-mode</code> to write my blog, and <code>org-publish</code> as my static site generator. While this system works great, I have found it to be really really slow. At this point, my blog has 39 posts, and <code>org-publish</code> will take upwards of a <i>minute</i> to re-generate all of them. To make matters worse, my workflow usually involves several re-generations per post. This gets old pretty quickly.
</p>

<p>
Since I am on a long train ride today, I decided to have a go at this problem. By the way, train rides and hacking on Emacs are a perfect match: Internet connectivity on trains is usually terrible, but Emacs is self-documenting, so internet access doesn't matter as much. It is sobering to work without an internet connection every once in a while, and Emacs is a perfect target for this kind of work.
</p>

<p>
One of the many things I learned on train rides is that Emacs in fact contains its own profiler! So, I ran <code>(progn (profiler-start 'cpu) (org-publish "blog") (profiler-report))</code> to get a hierarchical list of where <code>org-publish</code> was spending its time. Turns out, most of its total run time was spent in functions relating to version control (starting with <code>vc-</code>).
</p>

<p>
Some package in my configuration set up <code>vc-find-file-hook</code> as part of <code>find-file-hook</code>. This means that every time <code>org-publish</code> opens a file, Emacs will look for the containing git repository and query its status. This takes forever! Worse yet, I don't even use <code>vc-git</code> at all. All my git interaction is done through <code>magit</code>.
</p>

<p>
But Emacs wouldn't be Emacs if this could not be fixed with a line or two of elisp. <code>(remove-hook 'find-file-hooks 'vc-find-file-hook)</code> will do the trick. This brought the runtime of <code>org-publish</code> down to 15 seconds. Yay for profiling and yay for Emacs!
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-org-mode.html">org-mode</a> <a href="https://bastibe.de/tag-emacs.html">emacs</a> ]]></description>
  <category><![CDATA[org-mode]]></category>
  <category><![CDATA[emacs]]></category>
  <link>https://bastibe.de/2014-05-07-speeding-up-org-publishing.html</link>
  <guid>https://bastibe.de/2014-05-07-speeding-up-org-publishing.html</guid>
  <pubDate>Wed, 07 May 2014 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Snow Crash]]></title>
  <description><![CDATA[

<figure id="org28c3f0c">
<img src="http://bastibe.de/static/2014-05/snow-crash.jpg" alt="snow-crash.jpg">

</figure>

<p>
This is probably the one book that made me who I am. I bought this book in the English section of a Norwegian bookstore while on a bike trip there. I was just out of school and I had not decided yet what to do with my life. My English was just barely good enough to understand Snow Crash.
</p>

<p>
At its essence, Snow Crash introduced me to the idea of hacking. That is, hacking in the abstract sense of <i>using knowledge about the inner workings of things to influence the world</i>. At the time, I didn't know anything about software yet. Even though the main hero of the book is a master hacker and part of the book plays out in cyber space, it never really talks about the act of writing code. I would learn about that later.
</p>

<p>
Snow Crash was my red pill. Re-reading it today, after having been a professional software engineer for a few years, I can't overstate how influential this book has been in my life. It instilled in me the desire to understand the deep structures of things. And with that, the ability to influence and create the world around me. It set me on the path to becoming who I am today.
</p>

<p>
Snow Crash also served as my introduction to modern utopian cyberpunk. Even though I spent my youth playing video games and reading bad sci-fi, I still remember Snow Crash as my formal introduction to cyber space, virtual avatars, megacorporations, and light cycle races. And it told of the awesome power of reason.
</p>

<p>
If you haven't already, go read this book!
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-books.html">books</a> ]]></description>
  <category><![CDATA[books]]></category>
  <link>https://bastibe.de/2014-05-03-snow-crash.html</link>
  <guid>https://bastibe.de/2014-05-03-snow-crash.html</guid>
  <pubDate>Sat, 03 May 2014 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Sound in Python]]></title>
  <description><![CDATA[
<p>
Have you ever wanted to work with audio data in Python? I know I do. I want to record from the microphone, I want to play sounds. I want to read and write audio files. If you ever tried this in Python, you know it is kind of a pain.
</p>

<p>
It's not for a lack of libraries though. You can read sound files using <a href="http://docs.python.org/2/library/wave.html">wave</a>, SciPy provides <a href="http://docs.scipy.org/doc/scipy/reference/tutorial/io.html#module-scipy.io.wavfile">scipy.io.wavfile</a>, and there is a SciKit called <a href="http://scikits.appspot.com/audiolab">scikits.audiolab</a>. And except for <code>scikits.audiolab</code>, these return the data as raw <code>bytes</code>. Like, they parse the WAVE header and that is great and all, but you still have to decode your audio data yourself.
</p>

<p>
The same thing goes for playing/recording audio: <a href="http://people.csail.mit.edu/hubert/pyaudio/">PyAudio</a> provides nifty bindings to <a href="http://www.portaudio.com/">portaudio</a>, but you still have to decode your raw <code>bytes</code> by hand.
</p>

<p>
But really, what I want is something different: When I record from the microphone, I want to get a NumPy array, not <code>bytes</code>. You know, something I can work with! And then I want to throw that array into a sound file, or play it on a different sound card, or do some calculations on it!
</p>

<p>
So one fateful day, I was sufficiently frustrated with the state of things that I set out to create just that. Really, I only wanted to play around with <a href="http://cffi.readthedocs.org">cffi</a>, but that is beside the point.
</p>

<p>
So, lets read some audio data, shall we?
</p>

<div class="org-src-container">
<pre class="src src-python">import soundfile
data = soundfile.read('sad_song.wav')
</pre>
</div>

<p>
done. All the audio data is now available as a NumPy array in <code>data</code>. Just like that.
</p>

<p>
Awesome, isn't it?
</p>

<p>
OK, that was easy. So let's read only the first and last 100 frames!
</p>

<div class="org-src-container">
<pre class="src src-python">import soundfile
first = soundfile.read('long_song.flac', stop=100)
last = soundfile.read(start=-100)
</pre>
</div>

<p>
This really only read the first and last bit. Not everything in between!
</p>

<p>
Note that at no point I did explicitly open or close a file! This is Python! We can do that! When the <code>SoundFile</code> object is created, it opens the file. When it goes out of scope, it closes the file. It's as simple as that. Or just use <code>SoundFile</code> in a context manager. That works as well.
</p>

<p>
Oh, but I want to use the sound card as well! I want to record audio to a file!
</p>

<div class="org-src-container">
<pre class="src src-python">from pysoundcard import Stream
from pysoundfile import SoundFile, ogg_file, write_mode
with Stream() as s: # opens your default audio device
    # This is supposed to be a new file, so specify it completely
    f = SoundFile('happy_song.ogg', sample_rate=s.sample_rate,
                  channels=s.channels, format=ogg_file,
                  mode=write_mode)
    f.write(s.read(s.sample_rate)) # one second
</pre>
</div>

<p>
Read from the stream, write to a file. It works the other way round, too!
</p>

<p>
And that's really all there is to it. Working with audio data in Python is easy now!
</p>

<p>
Of course, there is much more you could do. You could create a callback function and be called every four[1] frames with new audio data to process. You could request your audio data as <code>int16</code>, because that would be totally awesome! You could use many different sound cards at the same time, and route stuff to and fro to your hearts desire! And you can run all this on Linux using ALSA or Jack, or on Windows using DirectSound or ASIO, or on Mac using CoreAudio[2]. And you already saw that you can read Wave files, OGG, FLAC or MAT-files[3].
</p>

<p>
You can download these libraries from <a href="https://pypi.python.org/pypi">PyPi</a>, or use the binary Windows installers on Github. Or you can look at the source on Github (<a href="https://github.com/bastibe/PySoundFile">PySoundFile</a>, <a href="https://github.com/bastibe/PySoundCard">PySoundCard</a>), because Open Source is awesome like that! Also, you might find some bugs, because I haven't found them all yet. Then, I would like you to open an issue on Github. Or if have a great idea of how to improve things, please let me know as well.
</p>

<p>
<b>UPDATE:</b> It used to be that you could use indexing on SoundFile objects. For various political reasons, this is no longer the case. I updated the examples above accordingly.
</p>

<p>
[1] You can use any block size you want. Less than 4 frames per block can be really taxing for your CPU though, so be careful or you start dropping frames.
[2] More precisely: Everything that <a href="http://www.portaudio.com/">portaudio</a> supports.
[3] More precisely: Everything that <a href="http://www.mega-nerd.com/libsndfile/">libsndfile</a> supports.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-python.html">python</a> <a href="https://bastibe.de/tag-audio.html">audio</a> ]]></description>
  <category><![CDATA[python]]></category>
  <category><![CDATA[audio]]></category>
  <link>https://bastibe.de/2013-11-27-audio-in-python.html</link>
  <guid>https://bastibe.de/2013-11-27-audio-in-python.html</guid>
  <pubDate>Wed, 27 Nov 2013 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Blogging with Emacs]]></title>
  <description><![CDATA[
<p>
When I first started blogging, it was on <a href="http://blogger.com">blogger.com</a> (on the now-abandoned domain <a href="http://daskrachen.com">daskrachen.com</a>). On blogger, writing new posts (back then) involved typing raw HTML into a web form. Not what I would call ideal. This improved somewhat when they introduced a fancy rich text editor that would automatically transform beautiful text into a horrible formatting mess.
</p>

<p>
Thus I switched. Getting my blog posts out of blogger was&#x2026; Let's just say that I lost anything I didn't have a plain-text backup of. And <a href="http://bastibe.de/2012-07-18-blogging-with-pelican.html">I switched</a> to <a href="http://pelican.readthedocs.org/en/3.3.0/">Pelican</a>, a static site generator written in Python. It worked beautifully, until I updated something, at which point it resorted to just throwing errors. Now I don't have anything in particular against Python stack traces, but these particular traces traced deep into stuff that was (then?) too complex for me to understand.
</p>

<p>
Thus I switched again. This time to <a href="https://github.com/redline6561/coleslaw">C()λ∈slaw■</a>, a static site generator written in Common Lisp. Mainly because I was interested in Common Lisp at the time. It worked really well. However, this was supposed to give me a chance to delve into Common Lisp, and I failed to understand C()λ∈slaw■'s code. Realistically though, this is probably not C()λ∈slaw■'s fault. My knowledge of Common Lisp is far from perfect.
</p>

<p>
Thus it was time to switch again. Having been enamored with Emacs for the last few years, it made sense to blog with Emacs as well. Besides, I am kind of fed up with the many conflicting flavors of Markdown out there and have switched my personal note-taking to <a href="http://orgmode.org/">Org mode</a> long ago. So let's set up Emacs and Org as a blogging platform!
</p>

<p>
Before we start though, a short disclaimer: This will be a very bare bones blogging engine. It will consist of some articles, a front page, an archive page, and an RSS feed. And you will have to manage the front page and RSS feed semi-manually. No tags, no fancy history. Just what you see here.
</p>

<p>
On the plus side, this will be implemented entirely within Emacs and very simple to understand. Writing a new blog post will be as simple as writing an Org file and hitting a key combination! And you will get all of Org's fancy syntax highlighting and export magic for free!
</p>

<p>
Getting the pages to work is rather simple: You have to create a "publishing project" that specifies a <code>base-directory</code> where your Org files live and a <code>publishing-directory</code>, where the HTML files are going to be stored. Since this is Emacs, you could make your publishing directory any TRAMP path you like and insta-publish your workings!
</p>

<p>
(BTW, I am using Org 8.2.2 and I believe you need at least 8.0 for these examples to work)
</p>

<div class="org-src-container">
<pre class="src src-elisp">(require 'ox-html)
(require 'ox-rss)
(require 'ox-publish)
(setq org-publish-project-alist
      '(("blog-content"
         :base-directory "~/Projects/blog/posts"
         :html-extension "html"
         :base-extension "org"
         :publishing-directory "~/Projects/blog/publish"
         :publishing-function (org-html-publish-to-html)
         :recursive t          ; descend into sub-folders?
         :section-numbers nil  ; don't create numbered sections
         :with-toc nil         ; don't create a table of contents
         :with-latex t         ; do use MathJax for awesome formulas!
         :html-head-extra ""   ; extra &lt;head&gt; entries go here
         :html-preamble ""     ; this stuff is put before your post
         :html-postamble ""    ; this stuff is put after your post
)))
</pre>
</div>

<p>
Now hit <code>M-x org-publish</code>, type in <code>blog-content</code>, and you have a blog! Awesome! We are done here.
</p>

<p>
Well, how about an archive page that lists all your previous blog entries?
</p>

<p>
Emacs can auto-generate this for you. Simply add these lines to <code>blog-content</code>:
</p>

<div class="org-src-container">
<pre class="src src-elisp">         :auto-sitemap t
         :sitemap-filename "archive.org"
         :sitemap-title "Archive"
         :sitemap-sort-files anti-chronologically
         :sitemap-style list
         :makeindex t
</pre>
</div>

<p>
Also, you can put something like
</p>

<div class="org-src-container">
<pre class="src src-html">&lt;a href="archive.html"&gt;Other posts&lt;/a&gt;
</pre>
</div>

<p>
into your <code>:html-postamble</code> to make every page link to this. You can also add your <a href="https://disqus.com/">Disqus</a> snippet there to enable comments.
</p>

<p>
Adding a front page is simple, too. My front page is simply a normal page called <i>index.org</i>, which contains links and slugs for every article I want to have on the front page. For example:
</p>

<div class="org-src-container">
<pre class="src src-org"> #+TITLE: RECENT POSTS

 * [[file:2013-05-30-speeding-up-matplotlib.org][Speeding up Matplotlib]]
 #+include: "~/Projects/blog/posts/2013-05-30-speeding-up-matplotlib.org" :lines "4-9"
 [[file:2013-05-30-speeding-up-matplotlib.org][read more...]]
</pre>
</div>

<p>
But a blog is more than just text. There are images and CSS, too. I keep all that stuff in a separate directory and use a separate publishing project to copy it over to the publishing directory. Just add to your <code>publishing-alist</code>:
</p>

<div class="org-src-container">
<pre class="src src-elisp">("blog-static"
 :base-directory "~/Projects/blog/static"
 :base-extension "png\\|jpg\\|css"
 :publishing-directory "~/Projects/blog/publish/static"
 :recursive t
 :publishing-function org-publish-attachment)
</pre>
</div>

<p>
Setting up the RSS feed works similarly. The RSS feed is created from a single Org file. Create a new publishing project and put it into your <code>publishing-alist</code>
</p>

<div class="org-src-container">
<pre class="src src-elisp">("blog-rss"
 :base-directory "~/Projects/blog/posts"
 :base-extension "org"
 :publishing-directory "~/Projects/blog/publish"
 :publishing-function (org-rss-publish-to-rss)
 :html-link-home "http://bastibe.de/"
 :html-link-use-abs-url t
 :exclude ".*"
 :include ("rss.org")
 :with-toc nil
 :section-numbers nil
 :title "Bastis Scratchpad on the Internet")
</pre>
</div>

<p>
Make sure to exclude this <code>rss.org</code> from the <code>blog-content</code> project by adding it's name to the <code>:exclude</code> variable though. This <code>rss.org</code> file should contain headlines for every blog post. Every headline needs a publishing date and a permalink as property and the body of the post as content:
</p>

<div class="org-src-container">
<pre class="src src-org"> * Speeding up Matplotlib
 :PROPERTIES:
 :RSS_PERMALINK: "http://bastibe.de/2013-05-30-speeding-up-matplotlib.html"
 :PUBDATE: &lt;2013-05-30&gt;
 :END:
 #+include: "~/Projects/blog/posts/2013-05-30-speeding-up-matplotlib.org" :lines "4-"
</pre>
</div>

<p>
I exclude the first three lines, since they only contain <code>#+title</code>, <code>#+date</code>, and <code>#+tags</code>. You should at least exclude the <code>#+title</code> line. Otherwise, <code>ox-rss</code> will get confused about which title to choose for the feed.
</p>

<p>
You can even create a meta publishing project that executes all three projects in one fell swoop!
</p>

<div class="org-src-container">
<pre class="src src-elisp">("blog"
 :components ("blog-content" "blog-static" "blog-rss"))
</pre>
</div>

<p>
There is one more thing that is kind of fiddly though: As I said, I use Disqus for comments, but I don't want to have comment boxes on the front page or the archive. Thankfully though, <code>ox-html</code> allows you to set <code>:html-preamble</code> and <code>:html-postamble</code> to a function, in which case that function can decide what pre/postamble to draw! The function can take an optional argument that contains a <code>plist</code> of article metadata. In this case, I decide on the <code>:title</code> metadata whether to print the archive link and Disqus, only the archive link, or neither:
</p>

<div class="org-src-container">
<pre class="src src-elisp">:html-postamble
(lambda (info)
  "Do not show disqus for Archive and Recent Posts"
  (cond ((string= (car (plist-get info :title)) "Archive")
         "")
        ((string= (car (plist-get info :title)) "Recent Posts")
         "&lt;div id=\"archive\"&gt;&lt;a href=\"archive.html\"&gt;Other posts&lt;/a&gt;&lt;/div&gt;")
        (t
    "&lt;div id=\"archive\"&gt;&lt;a href=\"archive.html\"&gt;Other posts&lt;/a&gt;&lt;/div&gt;
     &lt;div id=\"disqus_thread\"&gt;&lt;/div&gt;
     &lt;script type=\"text/javascript\"&gt;
     ..."
</pre>
</div>

<p>
This should get you started! For completeness, here is my complete configuration:
</p>

<div class="org-src-container">
<pre class="src src-elisp">(require 'ox-html)
(require 'ox-rss)
(require 'ox-publish)
(setq org-publish-project-alist
      '(("blog"
         :components ("blog-content" "blog-static" "blog-rss"))
        ("blog-content"
         :base-directory "~/Projects/blog/posts"
         :html-extension "html"
         :base-extension "org"
         :publishing-directory "~/Projects/blog/publish"
         :publishing-function (org-html-publish-to-html)
         :auto-sitemap t
         :sitemap-filename "archive.org"
         :sitemap-title "Archive"
         :sitemap-sort-files anti-chronologically
         :sitemap-style list
         :makeindex t
         :recursive t
         :section-numbers nil
         :with-toc nil
         :with-latex t
         :html-head-include-default-style nil
         :html-head-include-scripts nil
         :html-head-extra
         "&lt;link rel=\"alternate\" type=\"appliation/rss+xml\"
                href=\"http://bastibe.de/rss.xml\"
                title=\"RSS feed for bastibe.de\"&gt;
          &lt;link href='http://fonts.googleapis.com/css?family=Roboto&amp;subset=latin' rel='stylesheet' type='text/css'&gt;
          &lt;link href='http://fonts.googleapis.com/css?family=Ubuntu+Mono' rel='stylesheet' type='text/css'&gt;
          &lt;link href= \"static/style.css\" rel=\"stylesheet\" type=\"text/css\" /&gt;
          &lt;title&gt;Basti's Scratchpad on the Internet&lt;/title&gt;
          &lt;meta http-equiv=\"content-type\" content=\"application/xhtml+xml; charset=UTF-8\" /&gt;
          &lt;meta name=\"viewport\" content=\"initial-scale=1,width=device-width,minimum-scale=1\"&gt;"
         :html-preamble
         "&lt;div class=\"header\"&gt;
              &lt;a href=\"http://bastibe.de\"&gt;Basti's Scratchpad on the Internet&lt;/a&gt;
              &lt;div class=\"sitelinks\"&gt;
                  &lt;a href=\"http://alpha.app.net/bastibe\"&gt;alpha.app.net&lt;/a&gt;  | &lt;a href=\"http://github.com/bastibe\"&gt;Github&lt;/a&gt;
              &lt;/div&gt;
          &lt;/div&gt;"
         :html-postamble
         (lambda (info)
           "Do not show disqus for Archive and Recent Posts"
           (cond ((string= (car (plist-get info :title)) "Archive") "")
                 ((string= (car (plist-get info :title)) "Recent Posts")
                  "&lt;div id=\"archive\"&gt;&lt;a href=\"archive.html\"&gt;Other posts&lt;/a&gt;&lt;/div&gt;")
                 (t
             "&lt;div id=\"archive\"&gt;&lt;a href=\"archive.html\"&gt;Other posts&lt;/a&gt;&lt;/div&gt;
              &lt;div id=\"disqus_thread\"&gt;&lt;/div&gt;
              &lt;script type=\"text/javascript\"&gt;
              /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
              var disqus_shortname = 'bastibe';
              /* * * DON'T EDIT BELOW THIS LINE * * */
              (function() {
                var dsq = document.createElement('script');
                dsq.type = 'text/javascript';
                dsq.async = true;
                dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
                (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
                  })();
              &lt;/script&gt;
              &lt;noscript&gt;Please enable JavaScript to view the
                  &lt;a href=\"http://disqus.com/?ref_noscript\"&gt;comments powered by Disqus.&lt;/a&gt;&lt;/noscript&gt;
              &lt;a href=\"http://disqus.com\" class=\"dsq-brlink\"&gt;comments powered by &lt;span class=\"logo-disqus\"&gt;Disqus&lt;/span&gt;&lt;/a&gt;")))
         :exclude "rss.org\\|archive.org\\|theindex.org")
        ("blog-rss"
         :base-directory "~/Projects/blog/posts"
         :base-extension "org"
         :publishing-directory "~/Projects/blog/publish"
         :publishing-function (org-rss-publish-to-rss)
         :html-link-home "http://bastibe.de/"
         :html-link-use-abs-url t
         :exclude ".*"
         :include ("rss.org")
         :with-toc nil
         :section-numbers nil
         :title "Bastis Scratchpad on the Internet")
        ("blog-static"
         :base-directory "~/Projects/blog/static"
         :base-extension "png\\|jpg\\|css"
         :publishing-directory "~/Projects/blog/publish/static"
         :recursive t
         :publishing-function org-publish-attachment)))
</pre>
</div>

<p>
All other sources, including the source code to all blog posts, can be found on <a href="https://github.com/bastibe/bastibe.github.com">Github</a> (the <i>master</i> branch contains HTML, the <i>source</i> branch contains Org).
</p>

<p>
<b>Addendum:</b> I have since discovered that <code>org-rss-publish-to-rss</code> only handles top-level headlines, but disregards second-level or higher-level headlines. Thus, if you have a post with nested headlines, your RSS feed will only include the text of the top-level one. To fix this, I advised <code>org-rss-publish-to-rss</code> to use <code>org-html-headline</code> for non-top-level headlines like this:
</p>

<div class="org-src-container">
<pre class="src src-elisp">(defadvice org-rss-headline
  (around my-rss-headline (headline contents info) activate)
  "only use org-rss-headline for top level headlines"
  (if (&lt; (org-export-get-relative-level headline info) 2)
      ad-do-it
    (setq ad-return-value (org-html-headline headline contents info))))
</pre>
</div>

<p>
Now, the RSS feed includes the full text of all articles.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-emacs.html">emacs</a> <a href="https://bastibe.de/tag-blog.html">blog</a> ]]></description>
  <category><![CDATA[emacs]]></category>
  <category><![CDATA[blog]]></category>
  <link>https://bastibe.de/2013-11-13-blogging-with-emacs.html</link>
  <guid>https://bastibe.de/2013-11-13-blogging-with-emacs.html</guid>
  <pubDate>Wed, 13 Nov 2013 00:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Speeding up Matplotlib]]></title>
  <description><![CDATA[
<p>
For the record, <a href="http://matplotlib.org">Matplotlib</a> is awesome! Its output looks amazing, it is extremely configurable and very easy to use. What more could you want?
</p>

<p>
Well&#x2026; speed. If there is one thing I could criticize about Matplotlib, it is its relative slowness. To measure that, lets make a very simple line plot and draw some random numbers as quickly as possible:
</p>

<div class="org-src-container">
<pre class="src src-python">import matplotlib.pyplot as plt
import numpy as np
import time

fig, ax = plt.subplots()

tstart = time.time()
num_plots = 0
while time.time()-tstart &lt; 1:
    ax.clear()
    ax.plot(np.random.randn(100))
    plt.pause(0.001)
    num_plots += 1
print(num_plots)
</pre>
</div>

<p>
On my machine, I get about 11 plots per second. I am using <code>pause()</code> here to update the plot without blocking. The correct way to do this is to use <code>draw()</code> instead, but due to a bug in the Qt4Agg backend, you can't use it there. If you are not using the Qt4Agg backend, <code>draw()</code> is supposedly the correct choice.
</p>

<p>
For a single plot, ten plots per second is not terrible. But then, this is really the simplest case possible, so ten frames per second in the simplest case probably means bad things for not so simple cases.
</p>

<p>
One thing that really takes time here is creating all the axes and text labels over and over again. So let's not do that.
</p>

<p>
Instead of calling <code>clear()</code> and then <code>plot()</code>, thus effectively deleting everything about the plot, then re-creating it for every frame, we can keep an existing plot and only modify its data:
</p>

<div class="org-src-container">
<pre class="src src-python">fig, ax = plt.subplots()
line, = ax.plot(np.random.randn(100))

tstart = time.time()
num_plots = 0
while time.time()-tstart &lt; 1:
    line.set_ydata(np.random.randn(100))
    plt.pause(0.001)
    num_plots += 1
print(num_plots)
</pre>
</div>

<p>
which yields about 26 plots per second. Not bad for a simple change like this. The downside is that the axes are not re-scaled any longer when the data changes. Thus, they won't change their limits based on the data any more.
</p>

<p>
Profiling this yields some interesting results:
</p>

<table>


<colgroup>
<col  class="org-right">

<col  class="org-right">

<col  class="org-right">

<col  class="org-right">

<col  class="org-right">

<col  class="org-left">
</colgroup>
<tbody>
<tr>
<td class="org-right">ncalls</td>
<td class="org-right">tottime</td>
<td class="org-right">percall</td>
<td class="org-right">cumtime</td>
<td class="org-right">percall</td>
<td class="org-left">filename:lineno(function)</td>
</tr>

<tr>
<td class="org-right">15</td>
<td class="org-right">0.167</td>
<td class="org-right">0.011</td>
<td class="org-right">0.167</td>
<td class="org-right">0.011</td>
<td class="org-left">{built-in method sleep)</td>
</tr>
</tbody>
</table>

<p>
The one function that uses the biggest chunk of runtime is <code>sleep()</code>, of all things. Clearly, this is not what we want. Delving deeper into the profiler shows that this is indeed happening in the call do <code>pause()</code>. Then again, I <i>was</i> wondering if using <i>pause</i> really was a great idea for performance&#x2026;
</p>

<p>
As it turns out, <code>pause()</code> internally calls <code>fig.canvas.draw()</code>, then <code>plt.show()</code>, then <code>fig.canvas.start_event_loop()</code>. The default implementation of <code>fig.canvas.start_event_loop()</code> then calls <code>fig.canvas.flush_events()</code>, then sleeps for the requested time. To add insult to injury, it even insists on sleeping at least one hundredth of a second, which actually explains the profiler output of 0.167 seconds of <code>sleep()</code> for 15 calls very well.
</p>

<p>
Putting this all together now yields:
</p>

<div class="org-src-container">
<pre class="src src-python">fig, ax = plt.subplots()
line, = ax.plot(np.random.randn(100))

tstart = time.time()
num_plots = 0
while time.time()-tstart &lt; 1:
    line.set_ydata(np.random.randn(100))
    fig.canvas.draw()
    fig.canvas.flush_events()
    num_plots += 1
print(num_plots)
</pre>
</div>

<p>
which now plots about 40 frames per second. Note that the call to <code>show()</code> mentioned earlier can be omitted since the figure is already on screen. <code>flush_events()</code> just runs the Qt event loop, so there is probably nothing to optimize there.
</p>

<p>
The only thing left to optimize now is thus <code>fig.canvas.draw()</code>. What this really is doing is drawing all the artists contained in the <code>ax</code>. Those artists can be accessed using <code>ax.get_children()</code>. For a simple plot like this, the artists are:
</p>

<ul class="org-ul">
<li>the background <code>ax.patch</code></li>
<li>the line, as returned from the <code>plot()</code> function</li>
<li>the spines <code>ax.spines</code></li>
<li>the axes <code>ax.xaxis</code> and <code>ax.yaxis</code></li>
</ul>

<p>
What we can do here is to selectively draw only the parts that are actually changing. That is, at least the background and the line. To only redraw these, the code now looks like this:
</p>

<div class="org-src-container">
<pre class="src src-python">fig, ax = plt.subplots()
line, = ax.plot(np.random.randn(100))
plt.show(block=False)

tstart = time.time()
num_plots = 0
while time.time()-tstart &lt; 5:
    line.set_ydata(np.random.randn(100))
    ax.draw_artist(ax.patch)
    ax.draw_artist(line)
    fig.canvas.update()
    fig.canvas.flush_events()
    num_plots += 1
print(num_plots/5)
</pre>
</div>

<p>
Note that you have to add <code>fig.canvas.update()</code> to copy the newly rendered lines to the drawing backend.
</p>

<p>
This now plots about 500 frames per second. Five hundred times per second! Frankly, this is quite amazing!
</p>

<p>
Note that since we are only redrawing the background and the line, some detail in the axes will be overwritten. To also draw the spines, use <code>for spine in ax.spines.values(): ax.draw_artist(spine)</code>. To draw the axes, use <code>ax.draw_artist(ax.xaxis)</code> and <code>ax.draw_artist(ax.yaxis)</code>. If you draw all of them, you get roughly the same performance as <code>fig.canvas.draw()</code>. The axes in particular are quite expensive.
</p>

<p>
There is also <a href="http://stackoverflow.com/a/8956211/1034">a way</a> of drawing the complete figure once and copying the complete but empty background, then reinstating that and only plotting a new line on top of it. This is equally fast as the code above without any visual artifacts, but breaks if you resize the plot.
</p>

<p>
In conclusion, I am quite impressed with the flexibility of Matplotlib. Matplotlib by default values quality over performance. But if you really need the performance at some point, it is flexible and hackable enough to let you tweak it to your hearts content. Really, an amazing piece of technology!
</p>

<p>
<b>EDIT</b>: As it turns out, <code>fig.canvas.blit(ax.bbox)</code> is a bad idea since it leaks memory like crazy. What you should use instead is <code>fig.canvas.update()</code>, which is equally fast but does not leak memory.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-python.html">python</a> ]]></description>
  <category><![CDATA[python]]></category>
  <link>https://bastibe.de/2013-05-30-speeding-up-matplotlib.html</link>
  <guid>https://bastibe.de/2013-05-30-speeding-up-matplotlib.html</guid>
  <pubDate>Thu, 30 May 2013 10:50:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[A Python Primer for Matlab Users]]></title>
  <description><![CDATA[
<blockquote>
<p>
Why would you want to use Python over Matlab?
</p>
</blockquote>

<ul class="org-ul">
<li>Because Python is free and Matlab is not.</li>
<li>Because Python is a general purpose programming language and Matlab is not.</li>
</ul>

<p>
Let me qualify that a bit. Matlab is a very useful programming environment for numerical problems. For a very particular set of problems, Matlab is an awesome tool. For many other problems however, it is just about unusable. For example, you would not write a complex GUI program in Matlab, you would not write your blogging engine in Matlab and you would not write a web service in Matlab. You can do all that and more in Python.
</p>

<div id="outline-container-org2647147" class="outline-2">
<h2 id="org2647147">Python as a Matlab replacement</h2>
<div class="outline-text-2" id="text-org2647147">
<p>
The biggest strength of Matlab is its matrix engine. Most of the data you work with in Matlab are matrices and there is a host of functions available to manipulate and visualize those matrices. Python, by itself, does not have a convenient matrix engine. However, there are three packages (think Matlab Toolboxes) out there that will add this capability to Python:
</p>

<ul class="org-ul">
<li>Numpy (the matrix engine)</li>
<li>Scipy (matrix manipulation)</li>
<li>Matplotlib (plotting)</li>
</ul>

<p>
You can either grab the individual installers for <a href="http://python.org">Python</a>, <a href="http://numpy.org">Numpy</a>, <a href="http://scipy.org">Scipy</a> and <a href="http://matplotlib.org">Matplotlib</a> from their respective websites, or get them pre-packaged from <a href="https://code.google.com/p/pythonxy/">pythonxy()</a> or <a href="http://www.enthought.com/products/epd.php">EPD</a>.
</p>
</div>
</div>

<div id="outline-container-org998530d" class="outline-2">
<h2 id="org998530d">A 30,000 foot overview</h2>
<div class="outline-text-2" id="text-org998530d">
<p>
Like Matlab, Python is <i>interpreted</i>, that is, there is no need for a compiler and code can be executed at any time as long as Python is installed on the machine. Also, code can be copied from one machine to another and will run without change.
</p>

<p>
Like Matlab, Python is <i>dynamically typed</i>, that is, every variable can hold data of any type, as in:
</p>

<div class="org-src-container">
<pre class="src src-python">    # Python
    a = 5         # a number
    a = [1, 2, 3] # a list
    a = 'text'    # a string
</pre>
</div>

<p>
Contrast this with C, where you can not assign different data types to the same variable:
</p>

<div class="org-src-container">
<pre class="src src-c">    // C
    int a = 5;
    float b[3] = {1.0, 2.0, 3.0};
    char c[] = "text";
</pre>
</div>

<p>
Unlike Matlab, Python is <i>strongly typed</i>, that is, you can not add a number to a string.
In Matlab, adding a single number to a string will convert that string into an array of numbers, then add the single number to each of the numbers in the array. Python will simply throw an error.
</p>

<div class="org-src-container">
<pre class="src src-octave">    % Matlab
    a = 'text'
    b = a + 5 % [121 106 125 121]
</pre>
</div>

<div class="org-src-container">
<pre class="src src-python">    # Python
    a = 'text'
    b = a + 5 # TypeError: Can't convert 'int' object to str implicitly
</pre>
</div>

<p>
Unlike Matlab, every Python file can contain as many functions as you like. Basically, you can organize your code in as many files as you want. To access functions from other files, use <code>import filename</code>.
</p>

<p>
Unlike Matlab, Python is very quick to start. In fact, most operating systems automatically start a new Python process whenever you run a Python program and quit that process once the program has finished. Thus, every Python program behaves as if it indeed were an independent program. There is no need to wait for that big Matlab mother ship to start before writing or executing code.
</p>

<p>
Unlike Matlab, the source code of Python is readily available. Every detail of Python's inner workings is available to everyone. It is thus feasible and encouraged to actively participate in the development of Python itself or some add-on package. Furthermore, there is no dependence on some company deciding where to go next with Python.
</p>
</div>
</div>

<div id="outline-container-orgacec82c" class="outline-2">
<h2 id="orgacec82c">Reading Python</h2>
<div class="outline-text-2" id="text-orgacec82c">
<p>
When you start up Python, it is a rather empty environment. In order to do anything useful, you first have to <code>import</code> some functionality into your workspace. Thus, you will see a few lines of <code>import</code> statements at the top of every Python file. Moreover, Python has <i>namespaces</i>, so if you <code>import numpy</code>, you will have to prefix every feature of Numpy with its name, like this:
</p>

<div class="org-src-container">
<pre class="src src-python">    import numpy
    a = numpy.zeros(10, 1)
</pre>
</div>

<p>
This is clearly cumbersome if you are planning to use Numpy all the time. So instead, you can import all of Numpy into the global environment like this:
</p>

<div class="org-src-container">
<pre class="src src-python">    from numpy import *
    a = ones(30, 1)
</pre>
</div>

<p>
Better yet, there is a pre-packaged namespace that contains the whole Numpy-Scipy-Matplotlib stack in one piece:
</p>

<div class="org-src-container">
<pre class="src src-python">    from pylab import *
    a = randn(100, 1)
    plot(a)
    show()
</pre>
</div>

<p>
Note that Python does not plot immediately when you type <code>plot()</code>. Instead, it will collect all plotting information and only show it on the screen once you type <code>show()</code>.
</p>

<p>
So far, the code you have seen should look pretty familiar. A few differences:
</p>

<ul class="org-ul">
<li>No semicolons at the end of lines;
In order to print stuff to the console, use the <code>print()</code> function instead.</li>

<li>No <code>end</code> anywhere.
In Python, blocks of code are identified by indentation and they always start with a colon like so:</li>
</ul>

<div class="org-src-container">
<pre class="src src-python">    sum = 0
    for n in [1, 2, 3, 4, 5]:
        sum = sum + n
    print(sum)
</pre>
</div>

<ul class="org-ul">
<li>Function definitions are different.
They use the <code>def</code> keyword instead of <code>function</code>.
You don't have to name the output variable names in the definition and instead use <code>return()</code>.</li>
</ul>

<div class="org-src-container">
<pre class="src src-python">    # Python
    def abs(number):
        if number &gt; 0:
            return number
        else:
            return -number
</pre>
</div>

<div class="org-src-container">
<pre class="src src-octave">    % Matlab
    function [out] = abs(number)
        if number &gt; 0
            out = number
        else
            out = -number
        end
    end
</pre>
</div>

<ul class="org-ul">
<li>There is no easy way to write out a list or matrix.
Since Python only gains a matrix engine by importing Numpy, it does not have a convenient way of writing arrays or matrices.   This sounds more inconvenient than it actually is, since you are probably using mostly functions like <code>zeros()</code> or <code>randn()</code> anyway and those work just fine. Also, many places accept Python lists (like this <code>[1, 2, 3]</code>) instead of Numpy arrays, so this rarely is a problem. Note that you <i>must</i> use commas to separate items and can not use semicolons to separate lines.</li>
</ul>

<div class="org-src-container">
<pre class="src src-python">    # create a numpy matrix:
    m = array([[1, 2, 3],
               [4, 5, 6],
               [7, 8, 9]])
    # create a Python list:
    l = [1 2 3]
</pre>
</div>

<ul class="org-ul">
<li>Arrays access uses brackets and is numbered from 0.
Thus, ranges <i>exclude</i> the last number (see below).
Mostly, this just means that array access does not need any <code>+1</code> or <code>-1</code> when indexing arrays anymore.</li>
</ul>

<div class="org-src-container">
<pre class="src src-python">    a = linspace(1, 10, 10)
    one = a[0]
    two = a[1]

    # "6:8" is a range of two elements:
    a[6:8] = [70, 80] # &lt;-- a Python list!
</pre>
</div>
</div>
</div>

<div id="outline-container-org2f8dadb" class="outline-2">
<h2 id="org2f8dadb">Common traps</h2>
<div class="outline-text-2" id="text-org2f8dadb">
<ul class="org-ul">
<li>Array slicing does not copy.</li>
</ul>

<div class="org-src-container">
<pre class="src src-python">    a = array([1 2 3 4 5])
    b = a[1:4] # [2 3 4]
    b[1] = rand() # this will change a and b!
    # make a copy like this:
    c = array(a[1:4], copy=True) # copy=True can be omitted
    c[1] = rand() # changes only c
</pre>
</div>
<ul class="org-ul">
<li>Arrays retain their data type.
You can slice them, you can dice them, you can do math on them, but a 16 bit integer array will never lose its data type. Use <code>new = array(old, dtype=double)</code> to convert an array of any data type to the default <code>double</code> type (like in Matlab).</li>
</ul>

<div class="org-src-container">
<pre class="src src-python">    # pretend this came from a wave file:
    a = array([1000, 2000, 3000, 4000, 5000], dtype=int16)
    a = a * 10 # int16 only goes to 32768!
    # a is now [10000, 20000, 30000, -25536, -15536]
</pre>
</div>
</div>
</div>


<div id="outline-container-org245d05e" class="outline-2">
<h2 id="org245d05e">Going further</h2>
<div class="outline-text-2" id="text-org245d05e">
<p>
Now you should be able to read Python code reasonably well. Numpy, Scipy and Matplotlib are actually modeled after Matlab in many ways, so many functions will have a very similar name and functionality. A lot of the numerical code you write in Python will look very similar to the equivalent code in Matlab. For a more in-depth comparison of Matlab and Python syntax, head over to <a href="http://www.scipy.org/NumPy_for_Matlab_Users">the Numpy documentation for Matlab users</a>.
</p>

<p>
However, since Python is a general purpose programming language, it offers some more tools. To begin with, there are a few more data types like associative arrays, tuples (unchangeable lists), proper strings and a full-featured object system. Then, there is a plethora of add-on packages, most of which actually come with your standard installation of Python. For example, there are <a href="http://docs.python.org/3/library/internet.html">internet protocols</a>, <a href="http://www.riverbankcomputing.com/software/pyqt/intro">GUI programming frameworks</a>, <a href="https://people.csail.mit.edu/hubert/pyaudio/">real-time audio interfaces</a>, <a href="https://www.djangoproject.com/">web frameworks</a> and <a href="http://www.pygame.org/">game development libraries</a>. Even <a href="https://github.com/bastibe/bastibe.github.com/tree/source">this very blog</a> is created using a Python <a href="http://pelican.readthedocs.org">static site generator</a>.
</p>

<p>
Lastly, Python has a great <a href="http://docs.python.org/3/">online documentation site</a> including a <a href="http://docs.python.org/3.3/tutorial/">tutorial</a>, there are <a href="http://wiki.python.org/moin/PythonBooks">many books</a> <a href="http://www.learnpythonthehardway.org/">on Python</a> and there is a helpful <a href="http://wiki.python.org/moin/BeginnersGuide">Wiki on Python</a>. There is also a <a href="http://scipy.org/Cookbook">tutorial</a> and <a href="http://scipy.org/Getting_Started">documentation</a> for Numpy, Scipy and <a href="http://matplotlib.org/contents.html">Matplotlib</a>.
</p>

<p>
A great way to get to know any programming language is to solve the first few problems on <a href="https://projecteuler.net/">project euler</a>.
</p>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-python.html">python</a> <a href="https://bastibe.de/tag-matlab.html">matlab</a> ]]></description>
  <category><![CDATA[python]]></category>
  <category><![CDATA[matlab]]></category>
  <link>https://bastibe.de/2013-01-20-a-python-primer-for-matlab-users.html</link>
  <guid>https://bastibe.de/2013-01-20-a-python-primer-for-matlab-users.html</guid>
  <pubDate>Sun, 20 Jan 2013 10:55:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Real Time Signal Processing in Python]]></title>
  <description><![CDATA[
<p>
Wouldn't it be nice if you could do real time audio processing in a convenient programming language? Matlab comes to mind as a convenient language for signal processing. But while Matlab is pretty fast, it is really only fast for algorithms that can be vectorized. In audio however, we have many algorithms that need knowledge about the previous sample to calculate the next one, so they can't be vectorized.
</p>

<p>
But this is not going to be about Matlab. This is going to be about Python. Combine Python with Numpy (and Scipy and Matplotlib) and you have a signal processing system very comparable to Matlab. Additionally, you can do real-time audio input/output using PyAudio. PyAudio is a wrapper around PortAudio and provides cross platform audio recording/playback in a nice, pythonic way. (Real time capabilities were added in 0.2.6 with the help of yours truly).
</p>

<p>
However, this does not solve the problem with vectorization. Just like Matlab, Python/Numpy is only fast for vectorizable algorithms. So as an example, let's define an iterative algorithm that is not vectorizable:
</p>

<div id="outline-container-org90a6a5a" class="outline-2">
<h2 id="org90a6a5a">A Simple Limiter</h2>
<div class="outline-text-2" id="text-org90a6a5a">
<p>
A limiter is an audio effect that controls the system gain so that it does not exceed a certain threshold level. One could do this by simply cutting off any signal peaks above that level, but that sounds awful. So instead, the whole system gain is reduced smoothly if the signal gets too loud and is amplified back to its original gain again when it does not exceed the threshold any more. The important part is that the gain change is done <i>smoothly</i>, since otherwise it would introduce a lot of distortion.
</p>

<p>
If a signal peak is detected, the limiter will thus need a certain amount of time to reduce the gain accordingly. If you still want to prevent all peaks, the limiter will have to know of the peaks in advance, which is of course impossible in a real time system. Instead, the signal is delayed by a short time to give the limiter time to adjust the system gain before the peak is actually played. To keep this delay as short as possible, this "attack" phase where the gain is decreased should be very short, too. "Releasing" the gain back up to its original value can be done more slowly, thus introducing less distortion.
</p>

<p>
With that out of the way, let me present you a simple implementation of such a limiter. First, lets define a signal envelope \(e[n]\) that catches all the peaks and smoothly decays after them:
</p>

<p>
\[
e[n] = \max( |s[n]|, e[n-1] \cdot f_r )
\]
</p>

<p>
where \(s[n]\) is the current signal and \(0 < f_r < 1\) is a release factor.
</p>

<p>
If this is applied to a signal, it will create an envelope like this:
</p>


<figure id="orga3d5d04">
<img src="http://bastibe.de/static/2012-11/envelope.png" alt="envelope.png">

</figure>

<p>
Based on that envelope, and assuming that the signal ranges from -1 to 1, the target gain \(g_t[n]\) can be calculated using
</p>

<p>
\[
g_t[n] = \begin{cases}
    1 & e[n] < t \\
    1 + t - e[n] & e[n] > t
\end{cases}
\]
</p>

<p>
Now, the output gain \(g[n]\) can smoothly move towards that target gain using
</p>

<p>
\[
g[n] = g[n-1] \cdot f_a + g_t[n] \cdot (1-f_a)
\]
</p>

<p>
where \(0 < f_a \ll f_r\) is the attack factor.
</p>

<p>
Here you can see how that would look in practice:
</p>


<figure id="orge0e1ef9">
<img src="http://bastibe.de/static/2012-11/gain.png" alt="gain.png">

</figure>

<p>
Zooming in on one of the limited section reveals that the gain is actually moving smoothly.
</p>


<figure id="orgd494a34">
<img src="http://bastibe.de/static/2012-11/detail.png" alt="detail.png">

</figure>

<p>
This gain can now be multiplied on the delayed input signal and will safely keep that below the threshold.
</p>

<p>
In Python, this might look like this:
</p>

<div class="org-src-container">
<pre class="src src-python">    class Limiter:
        def __init__(self, attack_coeff, release_coeff, delay, dtype=float32):
            self.delay_index = 0
            self.envelope = 0
            self.gain = 1
            self.delay = delay
            self.delay_line = zeros(delay, dtype=dtype)
            self.release_coeff = release_coeff
            self.attack_coeff = attack_coeff

        def limit(self, signal, threshold):
            for i in arange(len(signal)):
                self.delay_line[self.delay_index] = signal[i]
                self.delay_index = (self.delay_index + 1) % self.delay

                # calculate an envelope of the signal
                self.envelope *= self.release_coeff
                self.envelope  = max(abs(signal[i]), self.envelope)

                # have self.gain go towards a desired limiter gain
                if self.envelope &gt; threshold:
                    target_gain = (1+threshold-self.envelope)
                else:
                    target_gain = 1.0
                self.gain = ( self.gain*self.attack_coeff +
                              target_gain*(1-self.attack_coeff) )

                # limit the delayed signal
                signal[i] = self.delay_line[self.delay_index] * self.gain
</pre>
</div>

<p>
Note that this limiter does not <i>actually</i> clip all peaks completely, since the envelope for a single peak will have decayed a bit before the target gain will have reached it. Thus, the output gain will actually be slightly higher than what would be necessary to limit the output to the threshold. Since the attack factor is supposed to be significantly smaller than the release factor, this does not matter much though.
</p>

<p>
Also, it would probably be more useful to define the factors \(f_a\) and \(f_r\) in terms of the time they take to reach their target and the threshold \(t\) in dB FS.
</p>
</div>
</div>

<div id="outline-container-orgf6d84f1" class="outline-2">
<h2 id="orgf6d84f1">Implementing audio processing in Python</h2>
<div class="outline-text-2" id="text-orgf6d84f1">
<p>
A real-time audio processing framework using PyAudio would look like this:
</p>

<p>
(<code>callback</code> is a function that will be defined shortly)
</p>

<div class="org-src-container">
<pre class="src src-python">    from pyaudio import PyAudio, paFloat32

    pa = PyAudio()

    stream = pa.open(format = paFloat32,
                     channels = 1,
                     rate = 44100,
                     output = True,
                     frames_per_buffer = 1024,
                     stream_callback = callback)

    while stream.is_active():
        sleep(0.1)

    stream.close()
    pa.terminate()
</pre>
</div>

<p>
This will open a <code>stream</code>, which is a PyAudio construct that manages input and output to/from one sound device. In this case, it is configured to use <code>float</code> values, only open one channel, play audio at a sample rate of 44100 Hz, have that one channel be output only and call the function <code>callback</code> every 1024 samples.
</p>

<p>
Since the <code>callback</code> will be executed on a different thread, control flow will continue immediately after <code>pa.open()</code>. In order to analyze the resulting signal, the <code>while stream.is_active()</code> loop waits until the signal has been processed completely.
</p>

<p>
Every time the <code>callback</code> is called, it will have to return 1024 samples of audio data. Using the class <code>Limiter</code> above, a sample counter <code>counter</code> and an audio signal <code>signal</code>, this can be implemented like this:
</p>

<div class="org-src-container">
<pre class="src src-python">    limiter = Limiter(attack_coeff, release_coeff, delay, dtype)

    def callback(in_data, frame_count, time_info, flag):
        if flag:
            print("Playback Error: %i" % flag)
        played_frames = counter
        counter += frame_count
        limiter.limit(signal[played_frames:counter], threshold)
        return signal[played_frames:counter], paContinue
</pre>
</div>

<p>
The <code>paContinue</code> at the end is a flag signifying that the audio processing is not done yet and the <code>callback</code> wants to be called again. Returning <code>paComplete</code> or an insufficient number of samples instead would stop audio processing after the current block and thus invalidate <code>stream.is_active()</code> and resume control flow in the snippet above.
</p>

<p>
Now this will run the limiter and play back the result. Sadly however, Python is just a bit too slow to make this work reliably. Even with a long block size of 1024 samples, this will result in occasional hickups and discontinuities. (Which the <code>callback</code> will display in the <code>print(...)</code> statement).
</p>
</div>
</div>

<div id="outline-container-org557fe10" class="outline-2">
<h2 id="org557fe10">Speeding up execution using Cython</h2>
<div class="outline-text-2" id="text-org557fe10">
<p>
The limiter defined above could be rewritten in C like this:
</p>

<div class="org-src-container">
<pre class="src src-c">    // this corresponds to the Python Limiter class.
    typedef struct limiter_state_t {
        int delay_index;
        int delay_length;
        float envelope;
        float current_gain;
        float attack_coeff;
        float release_coeff;
    } limiter_state;

    #define MAX(x,y) ((x)&gt;(y)?(x):(y))

    // this corresponds to the Python __init__ function.
    limiter_state init_limiter(float attack_coeff, float release_coeff, int delay_len) {
        limiter_state state;
        state.attack_coeff = attack_coeff;
        state.release_coeff = release_coeff;
        state.delay_index = 0;
        state.envelope = 0;
        state.current_gain = 1;
        state.delay_length = delay_len;
        return state;
    }

    void limit(float *signal, int block_length, float threshold,
               float *delay_line, limiter_state *state) {
        for(int i=0; i&lt;block_length; i++) {
            delay_line[state-&gt;delay_index] = signal[i];
            state-&gt;delay_index = (state-&gt;delay_index + 1) % state-&gt;delay_length;

            // calculate an envelope of the signal
            state-&gt;envelope *= state-&gt;release_coeff;
            state-&gt;envelope = MAX(fabs(signal[i]), state-&gt;envelope);

            // have current_gain go towards a desired limiter target_gain
            float target_gain;
            if (state-&gt;envelope &gt; threshold)
                target_gain = (1+threshold-state-&gt;envelope);
            else
                target_gain = 1.0;
            state-&gt;current_gain = state-&gt;current_gain*state-&gt;attack_coeff +
                target_gain*(1-state-&gt;attack_coeff);

            // limit the delayed signal
            signal[i] = delay_line[state-&gt;delay_index] * state-&gt;current_gain;
        }
    }
</pre>
</div>

<p>
In contrast to the Python version, the delay line will be passed to the <code>limit</code> function. This is advantageous because now all audio buffers can be managed by Python instead of manually allocating and deallocating them in C.
</p>

<p>
Now in order to plug this code into Python I will use Cython. First of all, a "Cython header" file has to be created that declares all exported types and functions to Cython:
</p>

<div class="org-src-container">
<pre class="src src-python">    cdef extern from "limiter.h":
        ctypedef struct limiter_state:
            int delay_index
            int delay_length
            float envelope
            float current_gain
            float attack_coeff
            float release_coeff

        limiter_state init_limiter(float attack_factor, float release_factor, int delay_len)
        void limit(float *signal, int block_length, float threshold,
                   float *delay_line, limiter_state *state)
</pre>
</div>

<p>
This is very similar to the C header file of the limiter:
</p>

<div class="org-src-container">
<pre class="src src-c">    typedef struct limiter_state_t {
        int delay_index;
        int delay_length;
        float envelope;
        float current_gain;
        float attack_coeff;
        float release_coeff;
    } limiter_state;

    limiter_state init_limiter(float attack_factor, float release_factor, int delay_len);
    void limit(float *signal, int block_length, float threshold,
               float *delay_line, limiter_state *state);
</pre>
</div>

<p>
With that squared away, the C functions are accessible for Cython. Now, we only need a small Python wrapper around this code so it becomes usable from Python:
</p>

<div class="org-src-container">
<pre class="src src-python">    import numpy as np
    cimport numpy as np
    cimport limiter

    DTYPE = np.float32
    ctypedef np.float32_t DTYPE_t

    cdef class Limiter:
        cdef limiter.limiter_state state
        cdef np.ndarray delay_line
        def __init__(self, float attack_coeff, float release_coeff,
                     int delay_length):
            self.state = limiter.init_limiter(attack_coeff, release_coeff, delay_length)
            self.delay_line = np.zeros(delay_length, dtype=DTYPE)

        def limit(self, np.ndarray[DTYPE_t,ndim=1] signal, float threshold):
            limiter.limit(&lt;float*&gt;np.PyArray_DATA(signal),
                       &lt;int&gt;len(signal), threshold,
                       &lt;float*&gt;np.PyArray_DATA(self.delay_line),
                       &lt;limiter.limiter_state*&gt;&amp;self.state)
</pre>
</div>

<p>
The first two lines set this file up to access Numpy arrays both from the Python domain and the C domain, thus bridging the gap. The <code>cimport limiter</code> imports the C functions and types from above. The <code>DTYPE</code> stuff is advertising the Numpy <code>float32</code> type to C.
</p>

<p>
The class is defined using <code>cdef</code> as a C data structure for speed. Also, Cython would naturally translate every C struct into a Python dict and vice versa, but we need to pass the struct to <code>limit</code> <i>and</i> have <code>limit</code> modify it. Thus, <code>cdef limiter.limiter_state state</code> makes Cython treat it as a C struct only. Finally, the <code>np.PyArray_DATA()</code> expressions expose the C arrays underlying the Numpy vectors. This is really handy since we don't have to copy any data around in order to modify the vectors from C.
</p>

<p>
As can be seen, the Cython implementation behaves nearly identically to the initial Python implementation (except for passing the <code>dtype</code> to the constructor) and can be used as a plug-in replacement (with the aforementioned caveat).
</p>

<p>
Finally, we need to build the whole contraption. The easiest way to do this is to use a setup file like this:
</p>

<div class="org-src-container">
<pre class="src src-python">    from distutils.core import setup
    from distutils.extension import Extension
    from Cython.Distutils import build_ext
    from numpy import get_include

    ext_modules = [Extension("cython_limiter",
                             sources=["cython_limiter.pyx",
                                      "limiter.c"],
                             include_dirs=['.', get_include()])]

    setup(
        name = "cython_limiter",
        cmdclass = {'build_ext': build_ext},
        ext_modules = ext_modules
        )
</pre>
</div>

<p>
With that saved as <i>setup.py</i>, <code>python setup.py build_ext --inplace</code> will convert the Cython code to C, and then compile both the converted Cython code and C code into a binary Python module.
</p>
</div>
</div>

<div id="outline-container-org16f1975" class="outline-2">
<h2 id="org16f1975">Conclusion</h2>
<div class="outline-text-2" id="text-org16f1975">
<p>
In this article, I developed a simple limiter and how to implement it in both C and Python. Then, I showed how to use the C implementation from Python. Where the Python implementation is struggling to keep a steady frame rate going even at large block sizes, the Cython version runs smoothly down to 2-4 samples per block on a 2 Ghz Core i7. Thus, real-time audio processing is clearly feasable using Python, Cython, Numpy and PyAudio.
</p>

<p>
You can find all the source code in this article at <a href="https://github.com/bastibe/simple-cython-limiter">https://github.com/bastibe/simple-cython-limiter</a>
</p>
</div>
</div>

<div id="outline-container-org2b31577" class="outline-2">
<h2 id="org2b31577">Disclaimer</h2>
<div class="outline-text-2" id="text-org2b31577">
<ol class="org-ol">
<li>I invented this limiter myself. I could invent a better sounding limiter, but this article is more about how to combine Python, Numpy, PyAudio and Cython for real-time signal processing than about limiter design.</li>
<li>I recently worked on something similar at my day job. They agreed that I could write about it so long as I don't divulge any company secrets. This limiter is not a descendant of any code I worked on.</li>
<li>Whoever wants to use any piece of code here, feel free to do so. I am hereby placing it in the public domain. Feel free to contact me if you have questions.</li>
</ol>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-python.html">python</a> <a href="https://bastibe.de/tag-audio.html">audio</a> ]]></description>
  <category><![CDATA[python]]></category>
  <category><![CDATA[audio]]></category>
  <link>https://bastibe.de/2012-11-02-real-time-signal-processing-in-python.html</link>
  <guid>https://bastibe.de/2012-11-02-real-time-signal-processing-in-python.html</guid>
  <pubDate>Fri, 02 Nov 2012 10:53:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[An error occurred loading this content. Try again later.]]></title>
  <description><![CDATA[
<p>
Since we moved, our Apple TV has been giving us trouble: we would rent a movie on the Apple TV, and instead of playing it, the Apple TV would just display
</p>

<blockquote>
<p>
An error occurred loading this content.
Try again later.
</p>
</blockquote>

<p>
Rebooting, then trying again, would sometimes solve the issue. Trying to play a trailer before trying to play the movie seemed to increase chances of the Apple TV actually downloading the movie, too.
</p>

<p>
Finally, some forum or other pointed me to the correct solution: For some reason, the Apple TV did not play nice with our ISP DNS server. Simply changing the DNS server in the Apple TV settings to one of the Google DNS servers (8.8.8.8 and 8.8.4.4) solved the issue. Any other DNS will probably work, too.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-apple-tv.html">apple-tv</a> ]]></description>
  <category><![CDATA[apple-tv]]></category>
  <link>https://bastibe.de/2012-11-01-apple-tv.html</link>
  <guid>https://bastibe.de/2012-11-01-apple-tv.html</guid>
  <pubDate>Thu, 01 Nov 2012 18:26:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Names]]></title>
  <description><![CDATA[
<blockquote>
<p>
Names are everywhere in software. We name our variables, our functions, our arguments, classes, and packages. We name our source files and the directories that contain them. We name our jar files and war files and ear files. We name and name and name. Because we do so much of it, we'd better do it well.
</p>
</blockquote>

<p>
&#x2013; from the Introduction to chapter 2 "Meaningful Names" of "Clean Code" by Robert C. Martin.
</p>

<p>
Indeed we name a lot of things in software. As The Structure and Interpretation of Computer Programs points out, the primary purpose of a function (lambda) is to provide names for its arguments that are independent of names elsewhere. A function provides a closure in which stuff has defined names. The closure itself can then be embedded into other closures to form composite structures. Take any complex program structure and decompose its names through all its lambdas and you will only find more names right until you reach turtles.
</p>

<p>
At its heart, programming is about naming things. If I squint my eyes a little, I can nearly convince myself that naming is really all there is. All the rest is just playing games with syntax.
</p>

<p>
It's situations like this that I realize that The Structure and Interpretation of Computer Programs really changed how I view programming.
</p>

<p>
If you like programming at all, I implore you to <a href="http://mitpress.mit.edu/sicp/full-text/book/book.html">read it</a>, or <a href="http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/video-lectures/">watch it</a>, or <a href="http://mitpress.mit.edu/books/structure-and-interpretation-computer-programs">buy it</a>. It really blew my mind.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-programming.html">programming</a> ]]></description>
  <category><![CDATA[programming]]></category>
  <link>https://bastibe.de/2012-10-28-names.html</link>
  <guid>https://bastibe.de/2012-10-28-names.html</guid>
  <pubDate>Sun, 28 Oct 2012 22:08:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Matlab, Mex, Homebrew and OS X 10.8 Mountain Lion]]></title>
  <description><![CDATA[
<p>
Now that I am a student again, I have to use Matlab again. Among the many joys of Matlab is the compilation of mex files.
</p>

<p>
Because it does not work. So angry.
</p>

<p>
Basically, <code>mex</code> does not work because it assumes that you have OS X 10.6 installed. In OS X 10.6 you had <code>gcc-4.2</code> and your system SDK was stored in <i>\/Developer\/SDKs\/MacOSX10.6.sdk</i>. However, as of 10.7 (I think), the <i>\/Developer</i> directory has been deprecated in favor of distributing the whole development environment within the App package of XCode. Also, <code>gcc</code> has been deprecated in favor of <code>clang</code>. While a <code>gcc</code> binary is still provided, <code>gcc-4.2</code> is not. Of course, that is what <code>mex</code> relies on. Lastly, <code>mex</code> of course completely disregards common system paths such as, say, <i>\/usr\/local\/bin</i>, so compiling against some homebrew library won't work.
</p>

<p>
At least these things are rather easy to fix, since all these settings are saved in a file called <i>mexopts.sh</i>, which is saved to <i>~\</i>.matlab\/R2012a\// by default. The relevant section on 64-bit OS X begins after <code>maci64)</code> and should look like this: (changes are marked by comments)
</p>

<div class="org-src-container">
<pre class="src src-makefile">    #----------------------------------------------------------------------------
                # StorageVersion: 1.0
                # CkeyName: GNU C
                # CkeyManufacturer: GNU
                # CkeyLanguage: C
                # CkeyVersion:
                CC='gcc' # used to be 'gcc-4.2'

                # used to be '/Developer/SDKs/MacOSX10.6.sdk'
                SDKROOT='/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk'
                MACOSX_DEPLOYMENT_TARGET='10.8' # used to be '10.5'
                ARCHS='x86_64'
                CFLAGS="-fno-common -no-cpp-precomp -arch $ARCHS -isysroot $SDKROOT -mmacosx-version-min=$MACOSX_DEPLOYMENT_TARGET"
                CFLAGS="$CFLAGS  -fexceptions"
                CFLAGS="$CFLAGS -I/usr/local/include" # Homebrew include path
                CLIBS="$MLIBS"
                COPTIMFLAGS='-O2 -DNDEBUG'
                CDEBUGFLAGS='-g'
    #
                CLIBS="$CLIBS -lstdc++"
                # C++keyName: GNU C++
                # C++keyManufacturer: GNU
                # C++keyLanguage: C++
                # C++keyVersion:
                CXX=g++ # used to be 'g++-4.2'
                CXXFLAGS="-fno-common -no-cpp-precomp -fexceptions -arch $ARCHS -isysroot $SDKROOT -mmacosx-version-min=$MACOSX_DEPLOYMENT_TARGET"
                CXXLIBS="$MLIBS -lstdc++"
                CXXOPTIMFLAGS='-O2 -DNDEBUG'
                CXXDEBUGFLAGS='-g'
    #
                # FortrankeyName: GNU Fortran
                # FortrankeyManufacturer: GNU
                # FortrankeyLanguage: Fortran
                # FortrankeyVersion:
                FC='gfortran'
                FFLAGS='-fexceptions -m64 -fbackslash'
                FC_LIBDIR=`$FC -print-file-name=libgfortran.dylib 2&gt;&amp;1 | sed -n '1s/\/*libgfortran\.dylib//p'`
                FC_LIBDIR2=`$FC -print-file-name=libgfortranbegin.a 2&gt;&amp;1 | sed -n '1s/\/*libgfortranbegin\.a//p'`
                FLIBS="$MLIBS -L$FC_LIBDIR -lgfortran -L$FC_LIBDIR2 -lgfortranbegin"
                FOPTIMFLAGS='-O'
                FDEBUGFLAGS='-g'
    #
                LD="$CC"
                LDEXTENSION='.mexmaci64'
                LDFLAGS="-Wl,-twolevel_namespace -undefined error -arch $ARCHS -Wl,-syslibroot,$SDKROOT -mmacosx-version-min=$MACOSX_DEPLOYMENT_TARGET"
                LDFLAGS="$LDFLAGS -bundle -Wl,-exported_symbols_list,$TMW_ROOT/extern/lib/$Arch/$MAPFILE"
                LDFLAGS="$LDFLAGS -L/usr/local/lib" # Homebrew library path
                LDOPTIMFLAGS='-O'
                LDDEBUGFLAGS='-g'
    #
                POSTLINK_CMDS=':'
    #----------------------------------------------------------------------------
</pre>
</div>

<p>
To summarize:
</p>

<ul class="org-ul">
<li>changed <code>gcc-4.2</code> to <code>gcc</code></li>
<li>changed <code>/Developer/SDKs/MacOSX10.6.sdk</code> to <code>/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk</code></li>
<li>changed <code>10.5</code> to <code>10.8</code></li>
<li>added <code>CFLAGS="$CFLAGS -I/usr/local/include"</code></li>
<li>changed <code>g++-4.2</code> to <code>g++</code></li>
<li>added <code>LDFLAGS="$LDFLAGS -L/usr/local/lib"</code></li>
</ul>

<p>
With those settings, the mex compiler should work and it should pick up any libraries installed by homebrew.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-matlab.html">matlab</a> ]]></description>
  <category><![CDATA[matlab]]></category>
  <link>https://bastibe.de/2012-10-20-matlab-mex-and-osx.html</link>
  <guid>https://bastibe.de/2012-10-20-matlab-mex-and-osx.html</guid>
  <pubDate>Sat, 20 Oct 2012 10:12:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[My Emacs customizations]]></title>
  <description><![CDATA[
<p>
I don't host my <code>.emacs</code> in a repository. I tried it for a while, but it did not work for me. I think repos are great for managing multiple divergent versions of the same source tree. However, my dotfiles should never diverge, they should just be kept in sync. This is what Dropbox is great at. So I use Dropbox instead of git.
</p>

<p>
One downside of that is that it is not as easy to provide a public link to my dotfiles. Or maybe it is. Here goes
</p>

<p>
<a href="https://bitbucket.org/bastibe/.emacs.d/src/">My <i>.emacs</i></a>
</p>

<p>
Now on to the meat of this post: Some customizations I made that I think are cool.
</p>

<div id="outline-container-org2cd85e7" class="outline-2">
<h2 id="org2cd85e7">When Emacs starts up, make it fit the left half of the screen</h2>
<div class="outline-text-2" id="text-org2cd85e7">
<p>
First, I need a function to set the size of a frame in terms of pixels. Emacs only provides <code>set-frame-size</code>, but that works on characters, not pixels.
</p>

<div class="org-src-container">
<pre class="src src-elisp">(defun set-frame-pixel-size (frame width height)
  "Sets size of FRAME to WIDTH by HEIGHT, measured in pixels."
  (let ((pixels-per-char-width (/ (frame-pixel-width) (frame-width)))
		(pixels-per-char-height (/ (frame-pixel-height) (frame-height))))
	(set-frame-size frame
					(floor (/ width pixels-per-char-width))
					(floor (/ height pixels-per-char-height)))))
</pre>
</div>

<p>
Next, a function that uses the above to set the frame size to exactly fit the left half of the screen. Note that the <code>excess-...</code> variables account for things like the menu bar, the dock or the task bar so you might have to adapt these values to your particular windowing environment. The values given here work for dockless OSX.
</p>

<div class="org-src-container">
<pre class="src src-elisp">(defun use-left-half-screen ()
  (interactive)
  (let* ((excess-width 32)
		 (excess-height 48)
		 (half-screen-width (- (/ (x-display-pixel-width) 2) excess-width))
		 (screen-height (- (x-display-pixel-height) excess-height)))
	(set-frame-pixel-size (selected-frame) half-screen-width screen-height)))
</pre>
</div>

<p>
Finally, when Emacs starts up, make it use half the screen. Just how I like it!
</p>

<div class="org-src-container">
<pre class="src src-elisp">(if window-system
	(use-left-half-screen))
</pre>
</div>
</div>
</div>

<div id="outline-container-org672f606" class="outline-2">
<h2 id="org672f606">Make shell split windows auto-resize</h2>
<div class="outline-text-2" id="text-org672f606">
<p>
Usually when you open a new split window in Emacs, it takes up half the frame. For some kinds of windows, I like them to be smaller. So here is a little snippet that shrinks some kinds of windows to 15 lines of height.
</p>

<div class="org-src-container">
<pre class="src src-elisp">(add-hook 'window-configuration-change-hook
		  (lambda ()
			(when (or (string-equal (buffer-name) "*Python*")
					  (string-equal (buffer-name) "*eshell*")
					  (string-equal (buffer-name) "*tex-shell*"))
			  (if (not (eq (window-height) 15))
				  (enlarge-window (- 15 (window-height)))))))
</pre>
</div>
</div>
</div>

<div id="outline-container-orgf7592ef" class="outline-2">
<h2 id="orgf7592ef">Create a new line above/below the current one</h2>
<div class="outline-text-2" id="text-orgf7592ef">
<p>
There is one feature of Vim that I really missed: <code>o~/~O</code>, which 'opens' a new line above or below the current one without changing the current line.
</p>

<div class="org-src-container">
<pre class="src src-elisp">(defun vi-open-line-above ()
  "Insert a newline above the current line and put point at beginning."
  (interactive)
  (unless (bolp)
    (beginning-of-line))
  (newline)
  (forward-line -1)
  (indent-according-to-mode))

(defun vi-open-line-below ()
  "Insert a newline below the current line and put point at beginning."
  (interactive)
  (unless (eolp)
    (end-of-line))
  (newline-and-indent))

(global-set-key (kbd "C-o") 'vi-open-line-below)
(global-set-key (kbd "M-o") 'vi-open-line-above)
</pre>
</div>
</div>
</div>

<div id="outline-container-org5c6249d" class="outline-2">
<h2 id="org5c6249d">When editing LaTeX, show PDF output in Emacs</h2>
<div class="outline-text-2" id="text-org5c6249d">
<p>
Emacs provides an awesome mode for editing LaTeX files. But isn't it sad that you always have to leave Emacs for viewing the PDF? Well, not any more.
</p>

<p>
This function will open or refresh a split window with the generated PDF file in it. Thus, when I edit LaTeX, I will hit C-c C-c to compile, then C-c C-v to see the PDF. All that without having to leave the LaTeX file.
</p>

<div class="org-src-container">
<pre class="src src-elisp">;; open/show pdf file within Emacs using doc-view-mode
(defun open-show-pdf ()
  (interactive)
  (let ((tex-buffer-name (buffer-name))
		(pdf-buffer-name (concat (TeX-master-file) ".pdf")))
	(if (get-buffer pdf-buffer-name)
		(switch-to-buffer-other-window pdf-buffer-name)
	  (find-file-other-window pdf-buffer-name))
	(if (not (eq major-mode 'doc-view-mode))
		(doc-view-mode))
	(doc-view-revert-buffer t t)
	(switch-to-buffer-other-window tex-buffer-name)))

(add-hook 'LaTeX-mode-hook
		  (lambda ()
			(define-key LaTeX-mode-map (kbd "C-c C-v") 'open-show-pdf)
			(visual-line-mode t)
			(turn-on-reftex))
		  t)
</pre>
</div>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-emacs.html">emacs</a> ]]></description>
  <category><![CDATA[emacs]]></category>
  <link>https://bastibe.de/2012-10-14-emacs-customizations.html</link>
  <guid>https://bastibe.de/2012-10-14-emacs-customizations.html</guid>
  <pubDate>Sun, 14 Oct 2012 09:14:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Text editing with confidence and Emacs]]></title>
  <description><![CDATA[
<p>
In college, I realized for the first time how a good text editor could save me serious time, when I dragged an image file into Textmate and it auto-inserted all the LaTeX boilerplate for a figure. A few years later, on my first job, I learned <a href="http://www.viemu.com/">Vim key bindings for Visual Studio</a> because I hated text editing in Visual Studio so much. This showed me another way how a good text editor could save me serious time. A year after that, I was bored and tried Emacs. With Emacs, I discovered the marvelous world of <a href="https://en.wikipedia.org/wiki/REPL">REPLs</a> and <a href="http://orgmode.org/">outlining</a>.
</p>

<p>
Note that this is not supposed to be a comparison between text editors. I have done that <a href="http://bastibe.de/text-editors.html">already</a>. This will be a collection of some of the coolest things my text editor of choice is capable of. Stuff I love!
</p>

<div id="outline-container-org64ab848" class="outline-2">
<h2 id="org64ab848">Text editing</h2>
<div class="outline-text-2" id="text-org64ab848">
<p>
In my admittedly short history of working with computers and text professionally I have realized a universal truth about the tools I like to use: A great tool is a tool I can trust. A tool I can use with confidence because I know that it will do what I want. Furthermore, a great tool is a tool that does what I want with a minimum amount of friction.
</p>

<p>
Here is one of my pet peeve with many text editors: Whenever I initiate a text search, a modal dialog box pops up where I have to enter the search phrase, then click a button to search for that word. In contrast <a href="http://www.gnu.org/software/emacs/manual/html_node/emacs/Incremental-Search.html#Incremental-Search">great</a> <a href="http://vimdoc.sourceforge.net/htmldoc/usr_03.html#03.8">text</a> <a href="http://docs.sublimetext.info/en/latest/search_and_replace/search_and_replace.html">editors</a> allow searching for text without changing to a different window and show the results immediately while entering the search string. This is very fast and precise. In fact, it is so useful that searching is one of the most popular means of text navigation in text editors that have it.
</p>

<p>
This is a theme that goes through all these features: I look for stuff that is fast and precise, because this will enable more powerful applications of seemingly simple techniques.
</p>
</div>
</div>

<div id="outline-container-org7013100" class="outline-2">
<h2 id="org7013100">Outlining and task management</h2>
<div class="outline-text-2" id="text-org7013100">
<p>
Outlining is writing an hierarchical list of stuff that can be reordered and sub-trees can be hidden. I tried some graphical outliners before. I did not quite see the point of it. Instead, I always kept my todo lists in simple <a href="http://daringfireball.net/projects/markdown/">Markdown</a> files. It worked well enough.
</p>

<p>
But with Emacs, I found out about <a href="http://orgmode.org">org-mode</a>, which is at its heart an outliner with a syntax somewhat like Markdown. It proved to be surprisingly powerful to be able to easily refile entries or whole sub-trees in my todo lists. Also, having trees be collapsible effectively enabled me to consolidate all my todo management into one file without that file becoming unmanageably big.
</p>

<p>
Add to that the more advanced task tracking features of org-mode, such as <a href="http://orgmode.org/features.html#clocking">time tracking</a> or <a href="http://orgmode.org/features.html#planning">advanced todo planning</a> and this has become one of the most pivotal tools I use daily.
</p>
</div>
</div>

<div id="outline-container-org35a1e8b" class="outline-2">
<h2 id="org35a1e8b">Shell interaction and operating system compatibility</h2>
<div class="outline-text-2" id="text-org35a1e8b">
<p>
Whenever my job required me to work on Windows, I often found it jarring to not have a command line available. Granted, there is <a href="http://cygwin.com/">Cygwin</a>, but that does not play with the Windows directory structure too well. Also, many programs behave slightly differently on Linux, Cygwin and OSX. Basically, it drove me nuts.
</p>

<p>
Again, Emacs came to the rescue though: <a href="http://www.gnu.org/software/emacs/manual/html_node/eshell/What-is-Eshell_003f.html">Eshell</a> is a shell implemented in Emacs with no external dependencies. Thus, it comes installed on all my machines and works the same way on every operating system. Sadly though, Eshell is not quite full-featured and compatibility with some shell programs is kind of rough. In particular, it does not work well with <code>less</code> like scrolling buffers. However, some of those, like <code>man</code> or <code>info</code> are automatically opened in a special mode in Emacs itself, so this is not as bad as it sounds.
</p>

<p>
At more than one point, Eshell probably saved my sanity.
</p>
</div>
</div>

<div id="outline-container-org7516e28" class="outline-2">
<h2 id="org7516e28">Git interaction</h2>
<div class="outline-text-2" id="text-org7516e28">
<p>
Source control is a crucial tool when working with source code. In college we used <a href="http://subversion.tigris.org/">SVN</a>. Even cooler is <a href="http://git-scm.com/">Git</a>, though the initial learning curve is pretty bad. Personally, I learned it by mucking around on the command line and breaking stuff there, then using <a href="http://www.git-tower.com/">Tower</a> to restore the repository to some sane state. Sadly though, Tower is OSX only, so I was kind of screwed on Windows and Linux.
</p>

<p>
Again, enter Emacs: Emacs has this magical mode called <a href="http://magit.github.com/magit/magit.html#Introduction">magit</a>, which builds an interactive git interaction program within Emacs. With magit, all the major git commands are just a keystroke away and diffs or logs are easily accessible, too. It really is a major feat!
</p>
</div>
</div>

<div id="outline-container-orge8cea8b" class="outline-2">
<h2 id="orge8cea8b">Grab bag</h2>
<div class="outline-text-2" id="text-orge8cea8b">
<ul class="org-ul">
<li>Emacs' integrated <a href="http://www.gnu.org/software/emacs/manual/html_node/ediff/Introduction.html">ediff</a> is a joy to use.</li>
<li>REPLs are one honking great idea and come with most language modes for dynamic languages in Emacs.</li>
<li>Emacs' <a href="http://www.gnu.org/software/auctex/">LaTeX mode</a> is amazingly powerful. Combine that with Emacs' ability to display PDF files <a href="http://www.gnu.org/software/emacs/manual/html_node/emacs/Document-View.html">graphically</a> in a buffer and you have an awesome LaTeX environment.</li>
<li>Emacs' documentation is wonderful. I learned many a trick just idly leafing through the built in Emacs documentation.</li>
<li>Built in package management for extensions is a great time saver. This is available in <a href="https://github.com/gmarik/vundle#about">Vim</a> and <a href="http://wbond.net/sublime_packages/package_control">Sublime Text</a> as an addon, too.</li>
<li>Lisp is indeed beautiful and elisp is quite joyful to program. I never really went beyond simple configuration in Vim. My <code>.emacs</code> file contains some quite sophisticated small programs though.</li>
</ul>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-emacs.html">emacs</a> ]]></description>
  <category><![CDATA[emacs]]></category>
  <link>https://bastibe.de/2012-10-13-emacs.html</link>
  <guid>https://bastibe.de/2012-10-13-emacs.html</guid>
  <pubDate>Sat, 13 Oct 2012 11:30:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[A Story about Schemes]]></title>
  <description><![CDATA[
<p>
<b>Disclaimer:</b> If you are a programmer, or wanting to be a programmer, or interested in programming, or, well, reading this, you should absolutely, positively watch the 1986 MIT lecture about <a href="http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/">The Structure and Interpretation of Computer Programs</a>. (Most conveniently available <a href="http://ia600401.us.archive.org/8/items/MIT_Structure_of_Computer_Programs_1986/">here</a>)
</p>

<p>
I tried reading <a href="http://mitpress.mit.edu/sicp/full-text/book/book.html">the book</a> numerous times, but it was too dry for my taste. The lecture however is juicy, brain-bending bliss. Especially if you don't know much functional programming yet. It certainly blew my mind. Frequently. Like, every ten minutes. Basically, I feel reborn as a programmer, with a new sense of what I am doing and how it should be done.
</p>

<p>
However, this is not about SICP, it is about Scheme, which happens to be the programming language that SICP uses to preach its sermons. Above all, Scheme beautiful. It is an astounding marriage of simplicity and power. It is also a mess in terms of implementations. There are dozens of implementations and they all implement a different, partly overlapping set of features that may or may not be part of the canonical Scheme&#x2013;if there is such a thing.
</p>

<p>
So, how to select the correct Scheme? Naively, I first chose the one SICP uses, <a href="http://www.gnu.org/software/mit-scheme/">MIT-Scheme</a>. However, I soon found out that it does not work well with Emacs (that is, it did not work at all with <code>scheme-mode</code> and <code>run-scheme</code>). Also, its prompt is weird: <code>]=&gt;</code>. Whatever.
</p>

<p>
So next, I tried <a href="http://dynamo.iro.umontreal.ca/~gambit/wiki/index.php/Main_Page">Gambit Scheme</a>, which works a lot better with Emacs. But then, I soon found out that it does not support functions like <code>filter</code>, which are kind of essential. I was quick to write my own version of that, but really, this stuff should be provided. Turns out, <code>filter</code> is part of a Scheme Request For Implementation, or SRFI. <code>filter</code> is part of SRFI1. There is a <a href="http://srfi.schemers.org/srfi-implementers.html">huge list</a> of different Schemes and the SRFIs they support. Also, there is a list of <a href="http://www.cs.utah.edu/~mflatt/benchmarks-20100126/log3/Benchmarks.html">Schemes sorted by performance</a>. With <a href="http://www.cs.utah.edu/%7Emflatt/benchmarks-20100126/log3/Benchmarks-plot.html">plots</a>, even. It's a mess.
</p>

<p>
So this left me profoundly confused. What Scheme would I use? Ideally, it should be fast, work with Emacs and implement a reasonable set of SRFIs. Homebrew lists these:
</p>

<table>


<colgroup>
<col  class="org-left">

<col  class="org-left">

<col  class="org-left">
</colgroup>
<tbody>
<tr>
<td class="org-left">bigloo</td>
<td class="org-left">chibi-scheme</td>
<td class="org-left">chicken</td>
</tr>

<tr>
<td class="org-left">gambit-scheme</td>
<td class="org-left">gauche</td>
<td class="org-left">guile</td>
</tr>

<tr>
<td class="org-left">kawa</td>
<td class="org-left">mit-scheme</td>
<td class="org-left">plt-racket</td>
</tr>

<tr>
<td class="org-left">scheme48</td>
<td class="org-left">scsh</td>
<td class="org-left">sisc-scheme</td>
</tr>

<tr>
<td class="org-left">stklos</td>
<td class="org-left">tinyscheme</td>
<td class="org-left">&#xa0;</td>
</tr>
</tbody>
</table>

<p>
Difficult decision. Frankly, I don't have an answer. That said, I found <code>plt-racket</code> to be a joy to work with. <code>(help filter)</code> will open your browser with the appropriate help page for <code>filter</code>. Amazing. Also, it implements <a href="http://srfi.schemers.org/srfi-implementers.html">a long list</a> of SRFIs that will probably satisfy my simplistic needs. And the <a href="http://docs.racket-lang.org/">documentation</a> is excellent. And then there is DrRacket, which is a nice REPL that comes right with <a href="http://racket-lang.org/">Racket</a>. I like it.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-scheme.html">scheme</a> ]]></description>
  <category><![CDATA[scheme]]></category>
  <link>https://bastibe.de/2012-09-20-story-about-schemes.html</link>
  <guid>https://bastibe.de/2012-09-20-story-about-schemes.html</guid>
  <pubDate>Thu, 20 Sep 2012 20:21:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Kindle.app not starting on a case-sensitive file system]]></title>
  <description><![CDATA[
<p>
So Kindle.app was updated through the App Store and did not start any more. It just crashed and the crash reporter came up.
</p>

<p>
A quick look at Console.app turns up a link to the actual crash report. And the crash report starts with
</p>

<pre class="example" id="org2dda16c">
    Dyld Error Message:
      Library not loaded: @executable_path/../Frameworks/libWEbCoreKRF.dylib
      Referenced from: /Applications/Kindle.app/Contents/Frameworks/libWebCoreViewer.dylib
      Reason: image not found
</pre>

<p>
<code>libWEbCoreKRF.dylib</code>? With a capitalized <code>E</code>? That looks very much like a spelling error. So, point your terminal to <code>/Applications/Kindle.app/Contents/Frameworks/</code>, type
</p>

<div class="org-src-container">
<pre class="src src-sh">    sudo ln -s libWebCoreKRF.dylib libWEbCoreKRF.dylib
</pre>
</div>

<p>
to create a symlink with the misspelled name. Done.
</p>

<p>
Kindle works again.
</p>

<p>
Spelling is hard, it seems.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-macos.html">macos</a> ]]></description>
  <category><![CDATA[macos]]></category>
  <link>https://bastibe.de/2012-09-13-Kindle-app-does-not-start.html</link>
  <guid>https://bastibe.de/2012-09-13-Kindle-app-does-not-start.html</guid>
  <pubDate>Thu, 13 Sep 2012 20:19:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[On the Virtue of Contributing to and Using Open Source Software]]></title>
  <description><![CDATA[
<p>
I am a mostly self-taught programmer. Apart from a few programming side jobs at the university, I have been programming professionally for the last two and a half years.
</p>

<p>
About two years ago, we wanted to buy a Matlab license for our company. However, our investors declined for dubious reasons. So I started looking for alternatives. Inspired by a good friend (thank you, Marc), I looked into Python. Python has this brilliant environment for <a href="http://numpy.scipy.org/">numpy</a> <a href="http://scipy.org/">scipy</a> and <a href="http://matplotlib.sourceforge.net/">matplotlib</a> that, for my particular purposes, rivals Matlab.
</p>

<p>
However, just like Matlab, Python lacked a way of playing real time audio out of the box. At the university, we used <a href="http://playrec.co.uk/">Playrec</a> for that purpose, which implements <a href="http://www.portaudio.com/">PortAudio</a> bindings for Matlab. Luckily, there was a similar package available for Python, called <a href="http://people.csail.mit.edu/hubert/pyaudio/">PyAudio</a>.
</p>

<p>
But, it had one crucial flaw: it only implemented blocking-mode audio I/O, so not much luck for my real time requirements. (Blocking mode means that whenever you want to play some audio, you have to wait until the piece of audio finishes playing before you can begin to play the next piece or do some computation. Clearly, you can not process audio while it is playing with such a scheme). After a lot of research, I figured that my best bet would be to dive in and add non blocking I/O to PyAudio.
</p>

<p>
At the time, I knew nothing of the Python C API (or Python, really), so those first attempts were riddled with subtle bugs and memory leaks. Nevertheless, it got the job done. I could play back audio in real time using Python!
</p>

<p>
This was a revelation to me: I could not only <i>use</i> a piece of software, I could also <i>change</i> it and mold it to my special needs!
</p>

<p>
Thus, I put up my changes on <a href="https://github.com/bastibe/PyAudio">github</a> and emailed the PyAudio maintainer. While the maintainer at the time did not have the time to incorporate my changes into the official PyAudio distribution, a few people discovered my version of it on github and contributed to it!
</p>

<p>
This, again, was a revelation to me: Not only could <i>I</i> change stuff other people did, wonderful people from around the world could collaborate and help each other. It always gave me a warm feeling of appreciation when some stranger on the internet chose to work with me!
</p>

<p>
Then, finally, I decided to take the plunge to Python 3. The main obstacle for this was that PyAudio did not support Python 3. So, again, I dove in and figured out how to make it compatible with Python 3. Again, I put the changes up on github and emailed the official PyAudio maintainer. This time, he took immediate notice and we started working on an official release of PyAudio including Python 3 support and non-blocking I/O.
</p>

<p>
And during those weeks, I had my third, and biggest, revelation about Open Source Software: The PyAudio maintainer is a brilliant mind, and I was humbled to find that I could learn a lot from this man.
</p>

<p>
<b>By working on Open Source Software, you can work with really smart people, and learn from them. And the fruits of that labor can serve as instructions to yet more people to learn from.</b>
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-open-source.html">open-source</a> ]]></description>
  <category><![CDATA[open-source]]></category>
  <link>https://bastibe.de/2012-09-08-on-the-virtue-of-oss.html</link>
  <guid>https://bastibe.de/2012-09-08-on-the-virtue-of-oss.html</guid>
  <pubDate>Sat, 08 Sep 2012 08:44:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Fixing Errors in Epydoc]]></title>
  <description><![CDATA[
<p>
I ran into this error twice now and wasted an hour both times, so it is time to put this on my universal scratchpad, i.e. this blog.
</p>

<p>
If you ever get this error when using <a href="http://epydoc.sourceforge.net/">epydoc</a>:
</p>

<pre class="example" id="orgcb72f57">
    UNEXPECTED ERROR:
    'Text' object has no attribute 'data'
</pre>

<p>
You are probably running a version of Python that is greater than the latest one that is supported by epydoc. This is because epydoc has not been updated since 2008 and Python 2.5.
</p>

<p>
Luckily, some <a href="http://www.agapow.net/programming/python/epydoc-go-boom">fine</a> <a href="http://stackoverflow.com/questions/6704770/epydoc-attributeerror-text-object-has-no-attribute-data">folks</a> on the internet have figured out how to fix these things.
</p>

<p>
Short answer: Find your <i>site-packages</i> directory:
</p>

<div class="org-src-container">
<pre class="src src-python">    from distutils.sysconfig import get_python_lib
	print(get_python_lib())
</pre>
</div>

<p>
Go there, navigate to the <i>epydoc\/markup</i> directory and change line 307 of the file <i>restructuredtext.py</i> from
</p>

<div class="org-src-container">
<pre class="src src-python">	m = self._SUMMARY_RE.match(child.data)
</pre>
</div>

<p>
to
</p>

<div class="org-src-container">
<pre class="src src-python">	try:
		m = self._SUMMARY_RE.match(child.data)
	except AttributeError:
		m = None
</pre>
</div>

<p>
This should fix that problem.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-python.html">python</a> ]]></description>
  <category><![CDATA[python]]></category>
  <link>https://bastibe.de/2012-08-28-errors-in-epydoc.html</link>
  <guid>https://bastibe.de/2012-08-28-errors-in-epydoc.html</guid>
  <pubDate>Tue, 28 Aug 2012 12:14:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Using a Raspberry Pi as a Time Capsule for Mountain Lion]]></title>
  <description><![CDATA[
<p>
A while ago, I bought a Time Capsule to take care of my backups. I can't say it has been smooth sailing. Every now and then, the Time Capsule would claim that the backup did fail. Sometimes a reboot would help, sometimes not. Sometimes <code>hdiutil</code> would be able to salvage the backups, sometimes not. Sometimes, the backup disk image would simply be corrupted and the only option would be to delete it and start over.
</p>

<p>
This might be bad luck or it might be due to a defective Time Capsule or it might be due to my computer. I have no idea. But the thing is, if I have to hack on my backup system anyway, lets do it in style, at least. So here goes:
</p>

<div id="outline-container-org85f242c" class="outline-2">
<h2 id="org85f242c">Ingredients: <a href="http://www.raspberrypi.org/">A Raspberry Pi</a>, an external hard drive, some patience</h2>
<div class="outline-text-2" id="text-org85f242c">
<p>
Format an SD card as described <a href="http://elinux.org/RPi_Easy_SD_Card_Setup">in the wiki</a>. I just installed the version of Debian that is provided on <a href="http://www.raspberrypi.org/downloads">the official website</a>. Now just boot up.
</p>

<p>
Next, I was stumped because I only have an Apple LED display and no convenient way of connecting the Raspberry Pi's HDMI output to the LED display's Mini Display Port. After some searching and a combination of three adapter cables, I finally got it connected and could see it boot. Really, I have no use whatsoever for the HDMI port on the Raspberry pi. So the first thing I did was to enable SSH, which luckily is available right there in the configuration utility that starts when you boot the thing for the first time.
</p>

<p>
After that, I disconnected the display and immediately was stumped because I now had no way of finding the Pi's IP address. Actually, I did not even have a network to connect it to. So I strung an ethernet cable from my laptop to the Pi and enabled <i>Internet Sharing</i> in order to (1) start the DHCP server and (2) give the Pi internet access. The IP address was then easily found using <code>arp -a</code>.
</p>
</div>
</div>

<div id="outline-container-orgc089e71" class="outline-2">
<h2 id="orgc089e71">Setting up the hard drive</h2>
<div class="outline-text-2" id="text-orgc089e71">
<p>
First off, I needed to format and mount my external hard drive to be usable as a Time Machine volume. <code>ls /dev</code> showed the hard drive as <code>/dev/sda</code>. Thus, I installed <code>parted</code> using <code>sudo apt-get install parted</code> and used it <code>sudo parted</code>. In parted, <code>select /dev/sda</code> sets it up to modify the external hard drive, <code>rm 1</code> deleted its main partition, <code>q</code> to quit parted. Next, creating a new partition: <code>sudo fdisk</code>, then in there <code>n</code> with <code>p</code> and <code>1</code> to create a new primary partition, then <code>w</code> to apply the changes and exit. Lastly, I created the file system with <code>sudo mkfs -t ext4 /dev/sda1</code> with the whole partition as its size. Now lastly, I created a mount point for it using <code>mkdir ~/TimeMachine</code> (don't use <code>sudo</code>!) and auto-mounted it by appending this to <i>/etc/fstab</i>
</p>

<pre class="example" id="org555ea67">
    /dev/sda1 /home/pi/TimeMachine ext4 rw,auto,user,exec,sync 0 0
</pre>

<p>
Note: <code>sync</code> specifies that all file system changes have to be written to disk immediately, without caching. This might be bad for performance, but on the other hand, this behavior is probably a good idea for a backup system. I once read something somewhere that Apple is enforcing a similar behavior on their Time Capsules and that this is the reason why they won't allow any other network drive as Time Capsules.
</p>
</div>
</div>

<div id="outline-container-org8a9d2df" class="outline-2">
<h2 id="org8a9d2df">Setting up the shared folder</h2>
<div class="outline-text-2" id="text-org8a9d2df">
<p>
First up, this requires <code>netatalk</code>, so I did <code>sudo apt-get update</code> and <code>sudo apt-get install netatalk</code> to install it. Next, netatalk has to be configured to actually share the drive on the network. This is accomplished by appending this line to <i>/etc/netatalk/AppleVolumes.default</i>:
</p>

<pre class="example" id="orge43fdab">
    /home/pi/TimeMachine TimeMachine allow:pi cnidscheme:dbd options:upriv,usedot,tm
</pre>

<p>
Also, the afp daemon should be configured to use the proper authentification schemes. Thus, add this to <i>/etc/netatalk/afpd.conf</i>:
</p>

<pre class="example" id="org95af516">
    - -transall -uamlist uams_randnum.so,uams_dhx.so,uams_dhx2.so -nosavepassword -advertise_ssh
</pre>

<p>
<del>(maybe append <code>mdns</code> to the hosts in <i>/etc/nsswitch.conf</i>? Probably not necessary.)</del>
</p>

<p>
<del>I am also not quite sure whether I actually had to create a new file <i>/etc/avahi/services/afpd.service</i> and write into it:</del>
</p>

<div class="org-src-container">
<pre class="src src-xml">    &lt;?xml version="1.0" standalone='no'?&gt;&lt;!--*-nxml-*--&gt;
    &lt;!DOCTYPE service-group SYSTEM "avahi-service.dtd"&gt;
    &lt;service-group&gt;
		&lt;name replace-wildcards="yes"&gt;%h&lt;/name&gt;
		&lt;service&gt;
			&lt;type&gt;_afpovertcp._tcp&lt;/type&gt;
			&lt;port&gt;548&lt;/port&gt;
		&lt;/service&gt;
		&lt;service&gt;
			&lt;type&gt;_device-info._tcp&lt;/type&gt;
			&lt;port&gt;0&lt;/port&gt;
			&lt;txt-record&gt;model=Xserve&lt;/txt-record&gt;
		&lt;/service&gt;
	&lt;/service-group&gt;
</pre>
</div>

<p>
<del>And maybe, you have to create an empty file that signifies the drive as Time Machine compatible using <code>touch ~/TimeMachine/.com.apple.timemachine.supported</code>.</del>
</p>

<p>
<b>Edit:</b> Turns out, all these were not necessary. Thank you, reader Philipp, for trying them out!
</p>

<p>
I certainly did all that, but I am not quite sure which of these steps were strictly necessary. If you know, please let me, too.
</p>

<p>
Anyway, with all that done, restart both the netatalk and the Bonjour daemon using <code>sudo /etc/init.d/netatalk restart</code> and <code>sudo /etc/init.d/avahi-daemon restart</code>.
</p>
</div>
</div>

<div id="outline-container-orgc93e2ef" class="outline-2">
<h2 id="orgc93e2ef">Setting up the Time Machine</h2>
<div class="outline-text-2" id="text-orgc93e2ef">
<p>
<del>Now, back to the Mac. In order to make Time Machine accept the new network share, run</del>
</p>

<p>
<del><code>defaults write com.apple.systempreferences TMShowUnsupportedNetworkVolumes 1</code></del>
</p>


<p>
<b>Edit:</b> Turns out, this setting is not necessary. OSX just picks the Raspberry Pi as a usable Time Machine drive by default.
</p>

<p>
Finally, the TimeMachine folder on the Raspberry Pi was available as one of the backup drives. Halleluja!
</p>

<p>
Now transfer speeds for the initial backup are not exactly what I would call fast, but this might not be the Pi's fault. For one thing, the Pi is reporting to only run at half load. For another thing, the external hard drive and its USB connection is probably not very speedy. And lastly, I seem to remember that initial backups always were slow. But really, only time will tell how well this thing can do the job of a Time Capsule.
</p>

<p>
Further testing shows that transfer speeds are very comparable to the Time Capsule. Thus, I declare this a raging success!
</p>

<p>
This article heavily steals from these fine folks on the internet:
</p>

<ul class="org-ul">
<li><a href="http://kremalicious.com/ubuntu-as-mac-file-server-and-time-machine-volume/">Matthias Kretschmann</a></li>
<li><a href="http://www.trollop.org/2011/07/23/os-x-10-7-lion-time-machine-netatalk-2-2/">Steffen L. Norgren</a></li>
<li><a href="http://www.mikepalmer.net/build-a-netatalk-time-machine-for-osx-lion-using-debian-6-0-squeeze/">Mike Palmer</a></li>
</ul>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-macos.html">macos</a> <a href="https://bastibe.de/tag-backup.html">backup</a> ]]></description>
  <category><![CDATA[macos]]></category>
  <category><![CDATA[backup]]></category>
  <link>https://bastibe.de/2012-07-29-using-raspberry-pi-as-time-machine.html</link>
  <guid>https://bastibe.de/2012-07-29-using-raspberry-pi-as-time-machine.html</guid>
  <pubDate>Sun, 29 Jul 2012 21:18:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[How Apple is Failing Me]]></title>
  <description><![CDATA[
<p>
I bought my first Apple computer in 2007 after a long time of gaming on Windows and a few years of Linux. In the beginning, I was just amazed at the consistency, practicality and sanity of the whole experience. I think I had a bad case of tinkeritis and neophilia in my Linux days, so this was probably to be expected.
</p>

<p>
Later, I marveled at the level of polish in the third party software ecosystem around Macs. Then I was just glad to have a slick GUI with actual Unix underpinnings. For reference, this happened in the time span from OS X 10.5 Leopard until 10.7 Lion. However, in that same time frame, I also noticed a gradual increase in problems. The computer seems to crash slightly more often, programs seemed to become more buggy, behavior less logical. At first, I marked this up as mostly a matter of my own increasing knowledge of the system, but as time went on, I became more and more convinced that it was actually the system getting worse, not myself becoming more sensitive.
</p>

<p>
So here are some of those problems:
</p>

<div id="outline-container-org1e9c4ca" class="outline-2">
<h2 id="org1e9c4ca">Lack of Uninstallers</h2>
<div class="outline-text-2" id="text-org1e9c4ca">
<p>
Computer people like to try new software. Some new software is crap. You should delete crap from your computer. Amazingly however, the Mac does not have any way of uninstalling some software.
</p>

<p>
At the moment, there are three ways of getting software on your Mac.
</p>

<ol class="org-ol">
<li>Install from the App Store. Installation and un-installation work through the App Store.</li>
<li>Install by dragging n <code>*.app</code> bundle onto your computer. Uninstall by deleting the bundle. Works fine unless the app installed some stuff outside the bundle.</li>
<li>Install by executing a <code>*.pkg</code> file. No way to uninstall whatsoever unless the developer provides a separate uninstall mechanism.</li>
</ol>

<p>
Really, this is beyond ridiculous. There is no way of uninstalling software that has been installed from a <code>*.pkg</code>. How the heck am I supposed to use my computer without uninstalling software? Seriously, Apple? Is this a joke?
</p>

<p>
(So as a rule, I will only install <code>*.pkg</code> if there is absolutely no other way. Most of the time, I use or abuse <a href="http://mxcl.github.com/homebrew/">homebrew</a> to mitigate this problem.)
</p>
</div>
</div>

<div id="outline-container-org40ef2a7" class="outline-2">
<h2 id="org40ef2a7">Failing Time Machine</h2>
<div class="outline-text-2" id="text-org40ef2a7">
<p>
So the Mac comes with this awesome backup solution called Time Machine. Just plug in your external hard drive, and it will magically keep all your data save, at all times. Better yet, buy a Time Capsule and this will happen over the wireless network so you don't even need to plug in that hard drive any more. Magic!
</p>

<p>
Except, every few weeks the Time Machine icon in the menu bar will have a small exclamation point, which indicates that something went wrong. Usually, it means that Time Machine somehow lost track of what it was doing and silently corrupted all backups beyond repair. This happens across several computers and Time Machines. The only solution is to delete all backups and start anew.
</p>

<p>
So, backups that are not backing up. How amazing is that?
</p>
</div>
</div>

<div id="outline-container-orgae6caac" class="outline-2">
<h2 id="orgae6caac">Living in the Cloud</h2>
<div class="outline-text-2" id="text-orgae6caac">
<p>
OS X is this astonishingly modern operating system, where all your email, contacts, calendars and settings are synced in the cloud, accessible from anywhere and any device or service you use. In theory.
</p>

<p>
Synchronization is cool. I used to live within the Googleverse, and all my contacts, calendars and email accounts would sync through Google to all my Apple devices. Life was good! Until things started to go bad. At some point, Mail.app lost an email or two. Not a big deal. Then iCal would not connect any more, and would need to be restarted every other day. And finally, Address Book deleted all my contacts from Google. Actually, it did not delete the whole contacts, just all the information inside them, and leave empty husks with only a name and maybe a partial email address.
</p>

<p>
I wish I was making this up. I tested this quite thoroughly. Whenever Contacts was set up to sync with Google, after a few days or weeks it would delete all my contacts. Of course, this being cloud backed, it would delete them everywhere on all my devices, without any backup or anything. Thankfully, Address Book on iOS seems to not have this problem.
</p>

<p>
Things can go wrong, I understand that. But deleting all my contacts? Not cool. Not. Cool.
</p>
</div>
</div>

<div id="outline-container-org3414e2e" class="outline-2">
<h2 id="org3414e2e">iPhoto</h2>
<div class="outline-text-2" id="text-org3414e2e">
<p>
My grandfather has this G4 PowerBook. He stores all his photos on it. So at one point, we just could not stand it any more to support his software problems and set him up with a newer MacBook (2007) just so we could at least roughly recreate his problems on our machines.
</p>

<p>
But to do that, we had to convert his old library from iPhoto 1876 to iPhoto 2008. iPhoto itself claims to be able to do that, and lo and behold, it magically imported the old library, started an update program, then another, then another, then another, then another, and updated the old library through the ages up to the most recent version. And everything seemed to work fine, all the albums were there, all the thumbnails looked right, just perfect. Except if you opened any image, it would only show black. I mean, I can understand that an import of a library that old does not work. But at least tell me so. Don't silently corrupt everything!
</p>

<p>
And then there was my own library, started in late 2007 and handed through different revisions of iPhoto to today. It countains about 25 Gb worth of photos. Funny enough, its size on disk is actually 65 Gb. What. The. Heck?
</p>

<p>
At this point, a giant <b>thank you</b> to the <a href="http://www.fatcatsoftware.com/iplm/">iPhoto Library Manager</a> by Fat Cat Software, which saved both my library and my sanity! Those guys rock!
</p>
</div>
</div>

<div id="outline-container-orgda94a4d" class="outline-2">
<h2 id="orgda94a4d">OS X Lion with Auto Save and Versions</h2>
<div class="outline-text-2" id="text-orgda94a4d">
<p>
The newest and brightest  in the land of Apple is OS X 10.7 Lion (at the time of writing). This amazing piece of software has a life-changing new feature: It friggin breaks one of the oldest tradition in computer history: Saving files.
</p>

<p>
Now normally, I would applaud this. Just save everything automatically and give me a sensible undo mechanism instead. Great!
</p>

<p>
However, in a stroke of genius, they also got rid of the possibility of <i>save as&#x2026;</i>, which is just an easy way of duplicating a document. Say, because you received it in an email and want to file it somewhere else on your hard drive. Or because the document is saved on a thumb drive and you want to copy it over to your hard drive. No sir, you have to navigate to the document in the finder and copy it by hand from there. Thank you for your patience.
</p>

<p>
But the worst offender is Preview. Every program on the Mac has this very handy <i>proxy icon</i> in the window title. Whenever a window is representing a file on your computer, it will show that very file in the title, so you can drag and drop it somewhere else. Except preview won't give you the actual document. Instead, it will give you an alias to that document. Which is worth <i>nothing at all</i> if you drag it into an email, your Dropbox or a thumb drive.
</p>

<p>
Or try to enable File sharing on your local network, which works <i>sometimes</i>, but not all the time. Or Internet Sharing, which might share your internet connection, or break your DNS settings. Or take Bluetooth, which for the life of me, I can not make work for tethering with my iPhone, even though the same works just fine with the iPad and other Macs. Or take networking in general, which every once in a while just completely breaks down on my company's network and just refuses to send or receive any data over the Ethernet cable until I reboot my computer.
</p>

<p>
I could go on. Let's just say that Lion increased my WTF-per-minute rate significantly.
</p>
</div>
</div>

<div id="outline-container-orgdaf0a76" class="outline-2">
<h2 id="orgdaf0a76">Performance, Memory and File System</h2>
<div class="outline-text-2" id="text-orgdaf0a76">
<p>
Lets talk performance. I can't really complain here. In my MacBook Pro I have four cores, eight Gb of memory and a fast, Apple-sanctioned SSD. Life is good. Except that I happen to use virtual machines a whole lot and regardless of whether I use Linux (Ubuntu, Fedora, OpenSuse) or Windows (7, 8) on there, they feel faster.
</p>

<p>
I mean, you don't feel the pain of starting applications much on OS X, because in general, you simply keep your programs running all the time. But even so, Firefox starts up on Windows in, like, no time at all, but takes noticeable time on OS X (same configuration and plugins). I have an SSD, so I mostly don't care, but still.
</p>

<p>
Or take boot times. Even in a virtual machine, both Windows 7 and 8 and Ubuntu 12.04 and Fedora 17 boot up in less than half a minute. In comparison, OS X Lion takes significantly longer, sometimes minutes. Again, you usually don't feel that pain too much because you don't reboot your Mac all that often (unless you run Bootcamp for gaming regularly). Still, OS X boot and shutdown times are downright shameful these days.
</p>

<p>
Lets run a few virtual machines. I have eight Gb of memory. Lets boot up a Windows VM and give it two Gb. Do anything you want, run Eclipse <i>and</i> Visual Studio <i>and</i> Firefox with loads of tabs <i>and</i> Steam. Windows will do just fine. Those two Gb are plenty for anything except gaming and photo/video editing. Do the same thing with Linux, same result. In fact, Linux will work just fine with even less memory. But OS X? Don't even <i>think</i> of running it with less than two Gb. Four Gb will give you a workable system if you don't run too many memory intensive applications. But start up XCode and Eclipse and you are done for. This is a huge waste.
</p>

<p>
And lastly, let's talk HFS+. Did you know that HFS+ has a global lock that prevents any program from accessing the hard drive while another program is doing so? That explains why OS X is so friggin slow on non-SSD drives. And did you ever notice that HFS+ is slowly corrupting your data, even if there are no power failures or anything? I fire up Disk Utility every so often and it will always find some file system corruptions. It rarely breaks stuff, but really, the file system is the very last part of my system I want to see failing randomly.
</p>
</div>
</div>

<div id="outline-container-org4775077" class="outline-2">
<h2 id="org4775077">So, what now?</h2>
<div class="outline-text-2" id="text-org4775077">
<p>
With all this love, why am I still using a Mac? Well, for one thing, the hardware is seriously great. I would love to see some laptop manufacturer build something equally sturdy, light and good looking as a MacBook Pro. I would love to see someone build a great touch pad into a non-Apple device. I would love to see Retina displays everywhere<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>. But I don't.
</p>

<p>
And then there is software. Where is <a href="http://www.git-tower.com/">Tower</a> for Windows or Linux? Or <a href="http://www.sparrowmailapp.com/">Sparrow</a> or <a href="http://tapbots.com/blog/tweetbot/tweetbot-for-mac">Tweetbot</a> or <a href="http://reederapp.com/mac/">Reeder</a> or <a href="http://www.pixelmator.com/">Pixelmator</a> or iPhoto? I'm not saying there are no alternatives, but I certainly have not been able to find any that were really up to the same level of polish.
</p>

<p>
That said, I have recently been playing around with Windows 8, Ubuntu 12.04 and Fedora 17 and I must say, I am quite taken with them. All of them. As for the next computer I am going to buy, I am doubtful if it will be an Apple computer again.
</p>
</div>
</div>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
As a matter of fact, I would love to see well enough to see Retina at all, but that is beside the point
</p></div></div>


</div>
</div><div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-macos.html">macos</a> ]]></description>
  <category><![CDATA[macos]]></category>
  <link>https://bastibe.de/2012-07-09-apple-is-failing-me.html</link>
  <guid>https://bastibe.de/2012-07-09-apple-is-failing-me.html</guid>
  <pubDate>Thu, 19 Jul 2012 19:49:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Blogging with Pelican (and not Octopress)]]></title>
  <description><![CDATA[
<p>
For a while now, I have been moving more and more services I use off Google. The reasons for that are manyfold, and few of them have anything to do with Google being evil or not&#x2013;just to get that out of the way.
</p>

<p>
One of the last holdouts has been <a href="http://daskrachen.com">my neglected Blogspot blog</a>. And one of the reasons for it being neglected is that it was hosted on Blogspot. Now don't get me wrong here, Blogspot is a terriffic blogging platform. You have this very nice nearly-WYSIWYG text editor right in your browser, you can upload images, you can publish instantly to your blog&#x2026; Basically everything is taken care of for you conveniently right there in your browser. Google Style.
</p>

<p>
Its just that I don't like to work that way. I like plain text. I like typing stuff into a plain text editor. I like to be in control. And Blogspot might be convenient, but it did not make me feel like I was in control. In fact, I lost at least one article to Blogspot for unknown reasons.
</p>

<p>
Enter static site generators. The idea is that instead of writing rich text into some website, you create you content however you want on your own computer, then use a static generator which converts it into a set of static HTML pages and upload those to your website. Now all of the creation process is happening on your computer. You are in control. Probably the most popular program to do that is <a href="https://github.com/mojombo/jekyll">Jekyll</a>.
</p>

<p>
The second part of the equation is some kind of publishing platform. With these static site generators, really any web server does that trick. Just push your generated HTML files to the server and be done with it. Even cooler is Github. Using <a href="http://pages.github.com/">Github pages</a>, you can use your existing Github account and infrastructure to publish your blog just by pushing the HTML to Github. This is seriously cool!
</p>

<p>
So, I set out and tried <a href="http://octopress.org/">Octopress</a>, which combines these two things into a nice blogging platform. Honestly though, I don't know much Ruby and all that <code>rake</code> workflow did not make me much more comfortable than pushing stuff into Blogspot.
</p>

<p>
Hence, I looked for alternatives. What I ended up with is <a href="http://pelican.notmyidea.org/">Pelican</a>, a very simple static site generator written in Python. Finally, this is a codebase that is easy enough for me to understand and modify. If there is any trouble with my blog, I will be (and have been) able to just look at the source code and figure out what is going wrong. I like this!
</p>

<p>
To publish a new blog post, I will start by writing the post in <a href="http://daringfireball.net/projects/markdown/">Markdown</a> (a format I understand), process it using the very simple command line <code>pelican -s my_config_file.py posts/</code>, and push the result to GitHub. Easy as pie. And I feel like I am in control again!
</p>

<p>
Actually, if this is just a bit too technical for you, check out <a href="http://calepin.co/">Calepin</a> instead. It uses the very same Pelican engine, but instead of fiddling with Git, you just put your markdown files into your Dropbox, and&#x2013;poof&#x2013;you magically have a Blog!
</p>

<p>
If you want to see my blog as a repo on Github, just <a href="https://github.com/bastibe/bastibe.github.com/">go have a look</a> (the <code>master</code> branch contains the HTML, the <code>source</code> branch contains the configuration and Markdown).
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-blog.html">blog</a> ]]></description>
  <category><![CDATA[blog]]></category>
  <link>https://bastibe.de/2012-07-18-blogging-with-pelican.html</link>
  <guid>https://bastibe.de/2012-07-18-blogging-with-pelican.html</guid>
  <pubDate>Wed, 18 Jul 2012 21:11:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[How to get solarized syntax highlighting on your blog]]></title>
  <description><![CDATA[
<p>
Yesterday, I spent a few hours creating a solarized like CSS file for use with my new blogging tool. You could just scrape the settings from this very website, but for convenience, here they are:
</p>

<div class="org-src-container">
<pre class="src src-c">/* Text */
.codehilite .t   { color: #586e75 }

/* Whitespace */
.codehilite .w   { color: #073642 }

/* Error */
.codehilite .err { color: #cb4b16; }

/* Keyword */
.codehilite .k   { color: #859900 }
.codehilite .kc  { color: #2aa198 } /* Keyword.Constant */
.codehilite .kd  { color: #268bd2 } /* Keyword.Declaration */
.codehilite .kn  { color: #b58900 } /* Keyword.Namespace */
.codehilite .kp  { color: #859900 } /* Keyword.Pseudo */
.codehilite .kr  { color: #073642 } /* Keyword.Reserved */
.codehilite .kt  { color: #b58900 } /* Keyword.Type */

/* Name */
.codehilite .n   { color: #586e75 }
.codehilite .na  { color: #2aa198 } /* Name.Attribute */
.codehilite .nb  { color: #268bd2 } /* Name.Builtin */
.codehilite .nc  { color: #268bd2 } /* Name.Class */
.codehilite .ne  { color: #cb4b16 } /* Name.Error */
.codehilite .no  { color: #2aa198 } /* Name.Constant */
.codehilite .nd  { color: #2aa198 } /* Name.Decorator */
.codehilite .ni  { color: #2aa198; font-weight: bold } /* Name.Entity */
.codehilite .nf  { color: #268bd2 } /* Name.Function */
.codehilite .nn  { color: #586e75; } /* Name.Namespace */
.codehilite .nt  { color: #2aa198; font-weight: bold } /* Name.Tag */
.codehilite .nv  { color: #cb4b16 } /* Name.Variable */

/* Builtin */
.codehilite .b   { color: #859900 }
.codehilite .bp  { color: #586e75 } /* Name.Builtin.Pseudo */

/* Variable */
.codehilite .v   { color: #586e75 }
.codehilite .vc  { color: #586e75 } /* Name.Variable.Class */
.codehilite .vg  { color: #268bd2 } /* Name.Variable.Global */
.codehilite .vi  { color: #268bd2 } /* Name.Variable.Instance */

/* Literal */

/* Literal.Number */
.codehilite .m { color: #268bd2 } /* Literal.Number */
.codehilite .mf { color: #268bd2 } /* Literal.Number.Float */
.codehilite .mh { color: #268bd2 } /* Literal.Number.Hex */
.codehilite .mi { color: #268bd2 } /* Literal.Number.Integer */
.codehilite .mo { color: #268bd2 } /* Literal.Number.Oct */

/* Literal.String */
.codehilite .s { color: #2aa198 }
.codehilite .sb { color: #2aa198 } /* Literal.String.Backtick */
.codehilite .sc { color: #2aa198 } /* Literal.String.Char */
.codehilite .sd { color: #2aa198 } /* Literal.String.Doc */
.codehilite .s2 { color: #2aa198 } /* Literal.String.Double */
.codehilite .se { color: #cb4b16 } /* Literal.String.Escape */
.codehilite .sh { color: #2aa198 } /* Literal.String.Heredoc */
.codehilite .si { color: #cb4b16 } /* Literal.String.Interpol */
.codehilite .sx { color: #2aa198 } /* Literal.String.Other */
.codehilite .sr { color: #cb4b16 } /* Literal.String.Regex */
.codehilite .s1 { color: #2aa198 } /* Literal.String.Single */
.codehilite .ss { color: #cb4b16 } /* Literal.String.Symbol */

/* Literal.Integer */
.codehilite .il { color: #268bd2 } /* Literal.Number.Integer.Long */

/* Operator */
.codehilite .o  { color: #586e75 }
.codehilite .ow { color: #859900 } /* Operator.Word */

/* Punctuation */
.codehilite .p  { color: #586e75 }

/* Comment */
.codehilite .c { color: #93a1a1; font-style: italic }
.codehilite .cm { color: #93a1a1; } /* Comment.Multiline */
.codehilite .cp { color: #93a1a1 } /* Comment.Preproc */
.codehilite .c1 { color: #93a1a1; } /* Comment.Single */
.codehilite .cs { color: #93a1a1; } /* Comment.Special */

.codehilite .hll { background-color: #dc322f }

/* Generic */
.codehilite .g { color: #586e75 }
.codehilite .gd { color: #586e75 } /* Generic.Deleted */
.codehilite .ge { font-style: italic } /* Generic.Emph */
.codehilite .gr { color: #586e75 } /* Generic.Error */
.codehilite .gh { color: #586e75; font-weight: bold } /* Generic.Heading */
.codehilite .gi { color: #586e75 } /* Generic.Inserted */
.codehilite .go { color: #586e75 } /* Generic.Output */
.codehilite .gp { color: #586e75 } /* Generic.Prompt */
.codehilite .gs { font-weight: 586e75 } /* Generic.Strong */
.codehilite .gu { color: #586e75; font-weight: bold } /* Generic.Subheading */
.codehilite .gt { color: #586e75 } /* Generic.Traceback */
</pre>
</div>

<div class="org-src-container">
<pre class="src src-c">code, pre {
	background: #fdf6e3;
	-webkit-box-shadow: inset 0 0 2px #000000;
	-moz-box-shadow: inset 0 0 2px #000000;
	box-shadow: inset 0 0 2px #000000;
	color: #586e75;
	margin-left: 0px;
	font-family: 'Droid Sans Mono', monospace;
	padding: 2px;
	-webkit-border-radius: 4px;
	-moz-border-radius: 4px;
	border-radius: 4px;
	-moz-background-clip: padding;
	-webkit-background-clip: padding-box;
	background-clip: padding-box;
}
</pre>
</div>

<p>
Keep in mind though that I have no formal knowledge of CSS whatsoever beyond what I could gather from these very files.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-blog.html">blog</a> ]]></description>
  <category><![CDATA[blog]]></category>
  <link>https://bastibe.de/2012-07-15-solarized-for-pygments.html</link>
  <guid>https://bastibe.de/2012-07-15-solarized-for-pygments.html</guid>
  <pubDate>Sun, 15 Jul 2012 14:33:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[How to gem install rlua on OSX/homebrew]]></title>
  <description><![CDATA[
<p>
If you want to use rlua, you need to have Lua installed. However, OSX does not come with Lua preinstalled, so you install it using
</p>

<p>
#+begin src sh
    brew install lua
#end<sub>src</sub>
</p>

<p>
Oh, would it be nice if everyone agreed on how to install stuff like this. Case in point, homebrew installs liblua (quite reasonable) in <code>/usr/local/lib/liblua.[5.1[.4]].dylib</code>
</p>

<p>
rlua however expects it to be called <code>liblua5.1.dylib</code> (notice the missing <code>.</code>).
</p>

<p>
Similarly, the headers are installed plainly into <code>/usr/local/include</code>, whereas rlua expects them to be in a folder called <code>lua5.1</code>.
</p>

<p>
Hence, here is how you get rlua to install:
</p>

<div class="org-src-container">
<pre class="src src-sh">    ln -s /usr/local/Cellar/lua/5.1.4/lib/liblua.5.1.4.dylib /usr/local/lib/liblua5.1.dylib
    ln -s /usr/local/Cellar/lua/5.1.4/include/ /usr/local/include/lua5.1
</pre>
</div>

<p>
Not exactly a beautiful solution, but it works.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-compiling.html">compiling</a> <a href="https://bastibe.de/tag-macos.html">macos</a> ]]></description>
  <category><![CDATA[compiling]]></category>
  <category><![CDATA[macos]]></category>
  <link>https://bastibe.de/2012-02-22-how-to-gem-install-rlua-on-osx-slash-homebrew.html</link>
  <guid>https://bastibe.de/2012-02-22-how-to-gem-install-rlua-on-osx-slash-homebrew.html</guid>
  <pubDate>Wed, 22 Feb 2012 11:43:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Text Editors]]></title>
  <description><![CDATA[
<p>
As far as I can tell, there has been a resurgence of development in the landscape of text editors of late. Only a few years ago, the text editing scene one the Mac seemed to be dominated by
</p>

<ul class="org-ul">
<li>Crazy unix farts using Vim or Emacs</li>
<li>BBEdit users</li>
<li>Textmate users</li>
</ul>

<p>
During a very short period of time though, a raft of new text editors became available. Sublime Text in particular has been getting a lot of attention and rave reviews by many people. To me, this warrants another look at what these new (and old) text editors are offering.
</p>

<div id="outline-container-orgfa976bd" class="outline-2">
<h2 id="orgfa976bd"><a href="http://www.vim.org/">Vim</a></h2>
<div class="outline-text-2" id="text-orgfa976bd">

<figure id="org06c7436">
<img src="http://bastibe.de/static/2012-02/vim_small.png" alt="vim_small.png">

</figure>

<p>
Vim is very old software. It is a more or less direct descendant of ed from the early 1970s. It grew up in text based terminals without any graphical windows or mouses. Hence, all of its functionality is really meant to be used from the keyboard only, even though mousing is supported these days.
</p>


<figure id="orgbb27a5f">
<img src="http://bastibe.de/static/2012-02/vim_window_small.png" alt="vim_window_small.png">

</figure>

<p>
The terminal inheritance limits its graphical capabilities somewhat. There are no graphical drawers or animations or pixel-precise scrolling. Everything is displayed in terms of rectangular characters, hence scrolling can only ever scroll one line at a time and there are no graphical images anywhere. Since Vim predates graphical displays altogether, it does not adhere to its standards much. In fact, in its normal mode it won't even type out the characters you hit on your keyboard.
</p>

<p>
This is at really Vim's greatest strength and weakness: In its 'normal mode', all key presses are interpreted like keyboard shortcuts in other programs. And what shortcuts there are! Pretty much every key on the keyboard has some special function, most keys even serve multiple functions depending on what mode you are in at the moment. Thus it should come as no surprise that you can do anything with these shortcuts at astounding speed. Watching a seasoned Vimmer do his keyboard dance is something to behold. Moving the cursor is especially powerful. Usually, any place in the current file is reachable using just a few key strokes. But of course, you are not limited to just viewing one file at a time either: Vim supports arbitrary split views and can even be used for efficient diffing or merging. And when it comes to changing that text, Vim is no slouch, either. There are various registers for saving text or locations, there is an increadibly powerful macro system, amazing searching capabilities, command line integration, there are specialized functions for programming… Really, when it comes to pure text editing chops, nothing beats Vim.
</p>


<figure id="orge2e039c">
<img src="http://bastibe.de/static/2012-02/vim_full_window_small.png" alt="vim_full_window_small.png">

</figure>

<p>
Vim is also incredibly customizable. Of course, there is no graphical preferences windows to do the customization in. You customize Vim by editing simple text files. Vim even includes its very own scripting language, VimScript, to enable users to extend it. There is a huge wealth of plugins available. These range from file browsers to support for new languages, or even some limited integration with compilers or source control tools. However, VimScript is not exactly a very pleasant language to code in and Vim does not actually like to interface with external tools much. These two issues limit the scope of what is possible with Vim somewhat–deep compiler integration and graphical debugging are fiddly at best, so you will probably just keep a terminal open and do them there. That said, the plugin ecosystem for Vim is probably still leaps and bounds beyond what is possible with most other text editor out there, but it does not quite reach the same breadth or integration as some IDEs or Emacs do.
All that power comes at a price. Learning Vim is hard. If you start out with Vim, it will probably take at least a week or so until you can approach your old productivity again. Mastering Vim will take years. Even after months and months of diligent learning, you will find some new tricks and features to increase your speed.
</p>

<p>
At the end of the day though, Vim is an amazingly powerful tool, and it is certainly worth it to at least learn the basics of it. Actually, most people I know who tried it have actually stuck with it. Myself, I have some two years of Vimming under my belt, too, and it has proven to be a very important tool for me.
</p>
</div>
</div>

<div id="outline-container-orgfd37b64" class="outline-2">
<h2 id="orgfd37b64"><a href="http://www.gnu.org/software/emacs/">Emacs 24</a></h2>
<div class="outline-text-2" id="text-orgfd37b64">

<figure id="orgb1a4dbe">
<img src="http://bastibe.de/static/2012-02/emacs_small.png" alt="emacs_small.png">

</figure>

<p>
The thing you have to realize about Emacs is that… Emacs is powerful. People have called it <a href="http://www.emacswiki.org/emacs/NealStephenson">the thermonuclear text editor</a>, and for a reason. Emacs can edit text, of course, but that is really only the most mundane of its features. Really, Emacs is a little world of its own. You can read and write your mail from within Emacs, you can do spreadsheets, calendaring, it can host terminals, debuggers, compilers, there is Tetris, hell, it even includes its very own psychiatrist! Speaking off the record here, I have a suspicion that Emacs might achieve sentience pretty soon.
</p>


<figure id="orgbde0fba">
<img src="http://bastibe.de/static/2012-02/emacs_window_small.png" alt="emacs_window_small.png">

</figure>

<p>
Similar to Vim, Emacs is old software. It was invented in the late 1970s at MIT and has been growing ever since. Also like Vim, its terminal inheritance shows its teeth sometimes: mouseweel scrolling can be awkward, especially if you like your inertial scrolling, the menu bar seems to not get much love and keyboard shortcuts are not conformant with what you might be used to from other text editors. On the other hand, Emacs has some very modern features like mixing of proportional fonts and fixed-width fonts or inline image display.
</p>

<p>
The upside of being old is that Emacs is very mature software. There is a ginormous selection of extensions available for Emacs, most of it actually distributed right with Emacs itself and a lot of it is superbly documented. Besides that, there are <a href="http://tromey.com/elpa/">several</a> <a href="http://marmalade-repo.org/">integrated</a> <a href="http://elpa.gnu.org/">repositories</a> for additional tools that can be downloaded and installed from the internet.
</p>

<p>
The real power of Emacs is in that it is really not so much a text editor but a virtual machine for a programming language called eLisp. Really anything that can possibly be written in Lisp and remotely involves text editing is possible and probably already available in Emacs. As such, Emacs probably has the most diverse feature set of any text editor out there. Most relevant to programmers will be debugger integration, automatic syntax and spell checking, powerful and context-aware autocompletion, refactoring capabilities and much much more. Emacs is the only program in this list which can actually be used as a full fledged IDE on its own.
</p>


<figure id="orgcf35143">
<img src="http://bastibe.de/static/2012-02/emacs_full_window_small.png" alt="emacs_full_window_small.png">

</figure>

<p>
But Emacs is not limited to programming at all. As mentioned before, it includes an Email client, a great calendar with an agenda, several IM clients, RSS readers, an <a href="http://orgmode.org/">astoundingly powerful outliner</a> and spreadsheet editor, it is frequently used for blogging, writing screen plays, books or really anything you can think of.
</p>

<p>
The only real downside to this is that Emacs is, well, old. There is great power there, but is is only accessible to those willing to learn the myriad key combinations to invoke it. Rellay, mastering Emacs is a task for years, not weeks. But of course, you are not forced to wield all the power Emacs has to offer at once. Getting up to speed with basic text editing in Emacs will only take a few minutes, and the built-in help system and tutorial will guide you further whenever you feel the need to explore.
</p>

<p>
I have been using Emacs for several months now and I am really enjoying it. It has a few shortcomings, but it is constantly being improved and getting more modern every day. I can see myself giving in to it and just live in Emacs all day long, but for now, I'm happy with it just being my primary text editor. However, I can't quite get beyond the fact that its pure text editing chops are nowhere near Vim. Then again, Emacs does <a href="http://gitorious.org/evil/pages/Home">support Vim key bindings</a>, so this might turn out not to bother me in the long run.
</p>

<p>
At any rate, I would recommend anyone to give Emacs a shot at least for a short while. The power of Emacs can be an exhilarating experience, really.
</p>
</div>
</div>

<div id="outline-container-orgb56c84a" class="outline-2">
<h2 id="orgb56c84a"><a href="http://macromates.com/">Textmate (2)</a></h2>
<div class="outline-text-2" id="text-orgb56c84a">

<figure id="orgeb9b5e1">
<img src="http://bastibe.de/static/2012-02/textmate_small.png" alt="textmate_small.png">

</figure>

<p>
For the longest time, all GUI text editors could generally be classified as either Vim-based, Emacs-based or shortcut-based. The prevalent crop of shortcut-based GUI text editors mapped all its advanced functions to certain modifier-letter combinations and/or menu bar items.
</p>

<p>
When Textmate was introduced, it introduced a new concept: snippets. Snippets are short pieces of text which, upon activating a certain trigger, would expand to arbitraryly complex constructs.
</p>

<p>
Thus, to define a class in some programming language, you would type <code>class</code>, then hit TAB, and it would expand to a complete class declaration with constructor, destructor and documentation. Further yet, the class name would be highlighted immediately, so you could start editing it to your liking. These edits would even automatically percolate to all the relevant places in the class declaration and thus automatically change all scope declarations and the like.
Or, you could drag some image file into some LaTeX code and it would expand (dragging being the trigger here) to a whole <code>\begin{figure}</code> complete with <code>\caption</code>, <code>\label</code>, the correct path to the image and everything else you need.
</p>

<p>
This has proven to be such a popular feature that since Textmate's inception, implementations of snippets have been developed for pretty much every IDE or text editor out there.
</p>


<figure id="org1c6e687">
<img src="http://bastibe.de/static/2012-02/textmate_window_small.png" alt="textmate_window_small.png">

</figure>

<p>
Textmate also featured a very flexible and easily extensible regex based syntax parser, beautiful color schemes, a very elegant project management system and a vibrant community extending it in many directions. This was even more fascinating in that most of this functionality was implemented using a convenient shell scripting engine that could utilize any programming language your shell supported.
</p>

<p>
Sadly though, its main developer got stuck somewhere along the way and development all but dried up for five years. This primarily meant that some issues just would not be fixed and thus, got all the more jarring. Most prominently, Textmate lacked split views, regex incremental search and would only do single character undo/redos. Many people left Textmate because of this lack of progress.
</p>

<p>
While I was in college, I used Textmate extensively and it proved to be a veritable tool for many editing tasks. It is somewhat limited in its integration with programming tools, though, so don't expect any complex compiler or debugger integration. Ultimately, I left it behind for lack of cross platform compatibility and lack of development. There used to be a Windows program called <a href="http://e-texteditor.com/">E Text Editor</a>, which wanted to become a fully compatible Textmate alternative for Windows and Linux, but development never even reached production quality.
</p>

<p>
Recently however, an early alpha version of Textmate 2 has been released that could reinvigorate the community and fix long standing issues. Whether that will actually happen will remain to be seen.
</p>
</div>
</div>

<div id="outline-container-orgbcfc392" class="outline-2">
<h2 id="orgbcfc392"><a href="http://www.vicoapp.com/">Vico</a></h2>
<div class="outline-text-2" id="text-orgbcfc392">

<figure id="orgc860ef1">
<img src="http://bastibe.de/static/2012-02/vico_small.png" alt="vico_small.png">

</figure>

<p>
Vico is a very new application that has spung to live only in 2011 and is not finished yet. It aims to be a modern Vim, combining the virtue of the powerful mode-based editing system of Vim with a modern Cocoa interface. It even merges Vim's editing capabilities with Textmate-derived snippets and syntax highlighting.
</p>

<p>
Really, it tries to be an organic symbiosis of Vim and Textmate. And for most purposes, it very much succeeds in this. Syntax highlighting is very solid, there is a code browser, a nice file browser and full support for Textmate snippets. Vico even includes a powerful scripting environment that enables you to extend it in a language called Nu, which has the interesting aspect of being able to call into every object or method in the Cocoa libraries, thus opening the doors to a boundless world of wonders. Its Vim integration is well on its way, too. The most notable omission at this point are macros. The developer is working on it though and has promised to implement them in the near future. Some other areas are lacking, too, but if development continues I see no reason why it should not become a very nice text editor.
</p>

<p>
As it stands though, development of Vico is going slow and its community is not very large yet. Vico is a very nice tool, but at the end of the day, I miss the raw power of an actual Vim just as I miss the vibrant community around Textmate. If you are not spoiled by Vim yet or find Vim just a bit too ugly for your taste, you could give Vico a try though.
</p>

<p>
Personally, I like it quite a bit and I am hoping very much that it will not be forgotten as a failed attempt to modernize Vim. That said, what with Sublime Text 2 including a limited support for Vim key bindings, I can't really see Vico taking off.
</p>
</div>
</div>

<div id="outline-container-orgaf6b5fd" class="outline-2">
<h2 id="orgaf6b5fd"><a href="http://www.sublimetext.com/">Sublime Text 2</a></h2>
<div class="outline-text-2" id="text-orgaf6b5fd">

<figure id="orga31ff2e">
<img src="http://bastibe.de/static/2012-02/sublimetext_small.png" alt="sublimetext_small.png">

</figure>

<p>
Sublime Text is a fairly recent development. It is a one-man project that has gained a lot of enthusiastic following in the last few months. In many ways, it feels like the next step in text editor development. Much like several other text editors out there, it has adopted Textmate snippets, color themes and syntax definitions as its core feature set. On top of that though, it has built a very powerful and flexible extension system that really sets it apart.
</p>

<p>
Do you remember CMD-T from Textmate? To open some file, you would hit CMD-T and start typing a file name. The name would be fuzzy matched to select from all available files. Thus, typing <code>bcc</code> would select <code>BeaconController.cpp</code>. This form of selection is increadibly intuitive and fast. It is also the basis for the extension system of Sublime Text. If there is no keyboard shortcut for a command, hit CMD-Shift-P and start typing to invoke the command.
</p>


<figure id="orgb54a27b">
<img src="http://bastibe.de/static/2012-02/sublimetext_window_small.png" alt="sublimetext_window_small.png">

</figure>

<p>
In very much the same way as M-x in Emacs (though with fuzzy matching), this can invoke arbitrarily complex commands such as <code>install bundle</code> or using some refactoring library. Additionally, the same mechanism can be used to jump to method names or opening files. Really, these features are very efficient implementations of a code browser and file browser.
</p>

<p>
The second big thing about Sublime Text is just the ridiculous amount of polish it received. For example, if you have two files with the same name, it will prefix the tab titles with the folder they reside in. Simple, but so useful! If you jump around in a file, there is always a subtle scrolling animation. Even simple text selections have slightly rounded borders and just look amazingly beautiful.
</p>

<p>
Also of note is that Sublime Text supports multiple cursors. Want to change then name of all occurrences of a variable? Just select them all (!) and change them all at once. This is another amazingly useful feature.
Its plugin system is based in Python, which is a refreshingly non-awkward choice for a text editor and spawned an astonishing amount of very interesting plugins already. Indeed the plugin system is flexible enough to support things like linters, source control integration and even something akin to Emacs's org-mode.
And it also supports <a href="http://www.sublimetext.com/docs/2/vintage.html">Vim key bindings</a>. Not very complete, but easily enough to be useful. Oh, and it is available cross-platform on Mac, Windows and Linux, too.
</p>

<p>
I think there are three big families of text editors: Emacs, Vim, and shortcut-based text editors. Since I discovered Textmate however, I started believing that it represents a new branch in the big tree of text editors. Sublime Text seems to be the next step in the evolution of the Textmate branch.
</p>

<p>
Really, Sublime Text is an amazing achievement. Maybe not quite as hackable as Emacs and not quite as flexible as Vim, but easily beating both in terms of elegance and modernity. If you don't want to learn Emacs or Vim, Sublime Text is what you should use. In fact, it is the first text editor ever that has tempted me to leave Emacs and Vim behind. Nuff said.
</p>
</div>
</div>

<div id="outline-container-orga8f66ee" class="outline-2">
<h2 id="orga8f66ee">What else is out there</h2>
<div class="outline-text-2" id="text-orga8f66ee">
<p>
Of course, that little list up there is by no means complete. Neither does it list all the amazing features these text editors have to offer, nor does it represent an exhaustive list of them. To the best of my knowledge, this is a short list of other text editors for the Mac platform. Note however, that I have never used any of them extensively and can only tell you stuff from heresay.
</p>
</div>

<div id="outline-container-org76dd8d5" class="outline-3">
<h3 id="org76dd8d5"><a href="http://www.barebones.com/products/bbedit/index.html">BBEdit</a></h3>
<div class="outline-text-3" id="text-org76dd8d5">

<figure id="org81cb12c">
<img src="http://bastibe.de/static/2012-02/bbedit.png" alt="bbedit.png">

</figure>

<p>
BBEdit is the big daddy of Mac text editors. It is currently available in version 10 and has a huge follwing predominantly amongst web developers. As far as I can tell, it includes amazing features for editing HTML. Maybe amongst the best out there.
The remainder of its feature set seems rather standard crop though. There is some support for compilation, source code control, snippets, plugins… Though nothing on the level of Vim or Emacs really. Its most important disadvantage is probably its lack of cross-platform availability and extensibility.
</p>
</div>
</div>

<div id="outline-container-orgefc7665" class="outline-3">
<h3 id="orgefc7665"><a href="http://www.barebones.com/products/textwrangler/">TextWrangler</a></h3>
<div class="outline-text-3" id="text-orgefc7665">

<figure id="orgae7025e">
<img src="http://bastibe.de/static/2012-02/textwrangler.png" alt="textwrangler.png">

</figure>

<p>
TextWrangler is the free smaller brother of BBEdit. Its feature set is somewhat pared down in comparison with BBEdit. In particular, it is missing BBEdit's famous HTML magic and some advanced external tool integration.
Even for free, there are probably more capable candidates available, though maybe not at the same level of platform integration. That said, TextWrangler is not a bad choice and probably just fine for some casual text editing.
</p>
</div>
</div>

<div id="outline-container-org57eadfd" class="outline-3">
<h3 id="org57eadfd"><a href="http://www.jedit.org/">JEdit</a></h3>
<div class="outline-text-3" id="text-org57eadfd">

<figure id="orgec27da1">
<img src="http://bastibe.de/static/2012-02/jedit.png" alt="jedit.png">

</figure>

<p>
I really don't know much about JEdit other than that it is written in Java, it has a sizeable following and it is available cross-platform. It seems like it could be about as useful as any shortcut based text editor can ever be, which is no small achievement. Also, it features a rich plugin system, of which I only heard good things.
For all I know, this could be a very worthy alternative if you are on a budget (no Sublime Text) and don't want to learn Emacs or Vim.
</p>
</div>
</div>

<div id="outline-container-org6873213" class="outline-3">
<h3 id="org6873213"><a href="http://chocolatapp.com/">Chocolat</a></h3>
<div class="outline-text-3" id="text-org6873213">

<figure id="org7fffca8">
<img src="http://bastibe.de/static/2012-02/chocolat.png" alt="chocolat.png">

</figure>

<p>
Chocolat is yet another text editor that came into being in the post-Textmate void. It offers a good range of standard features, though notably missing advanced plugins apparently. Apart from that, it seems to be a solid shortcut based Mac text editor that is relatively cheap and actively developed.
</p>
</div>
</div>

<div id="outline-container-orge8c7868" class="outline-3">
<h3 id="orge8c7868"><a href="http://www.kodapp.com/">Kod</a></h3>
<div class="outline-text-3" id="text-orge8c7868">

<figure id="orgc0e4d6d">
<img src="http://bastibe.de/static/2012-02/kod.png" alt="kod.png">

</figure>

<p>
Kod started out as an open source alternative to Textmate. This is quite uncommon for a post-Textmate text editor and worth supporting. After a good start however, the developer found a new job and development has pretty much stalled.
</p>
</div>
</div>

<div id="outline-container-orge741b98" class="outline-3">
<h3 id="orge741b98"><a href="http://www.codingmonkeys.de/subethaedit">SubEthaEdit</a></h3>
<div class="outline-text-3" id="text-orge741b98">

<figure id="orgbbd0c89">
<img src="http://bastibe.de/static/2012-02/subethaedit.png" alt="subethaedit.png">

</figure>

<p>
The great thing about SubEthaEdit is collaborative editing. if you want to edit text collaboratively with several people, SubEthaEdit performs the task seamlessly and elegantly.
Beyond that, it is a capable shortcut-based text editor. If you don't need the collaboration feature, you should probably look elsewhere though.
</p>
</div>
</div>

<div id="outline-container-org3c6df07" class="outline-3">
<h3 id="org3c6df07"><a href="http://www.peterborgapps.com/smultron/">Smultron</a></h3>
<div class="outline-text-3" id="text-org3c6df07">

<figure id="orgd23558e">
<img src="http://bastibe.de/static/2012-02/smultron.png" alt="smultron.png">

</figure>

<p>
Another venerable veteran on the Mac, Smultron used to be a free open source text editor that had a sizeable following. However, the developer ceased development at some point and later restarted the effort as a paid app in the Mac App Store.
Smultron lost most of its following in that transition.
</p>
</div>
</div>

<div id="outline-container-orgae2b7e9" class="outline-3">
<h3 id="orgae2b7e9"><a href="http://www.slickedit.com/products/slickedit">SlickEdit</a></h3>
<div class="outline-text-3" id="text-orgae2b7e9">

<figure id="org1c10e8d">
<img src="http://bastibe.de/static/2012-02/slickedit.png" alt="slickedit.png">

</figure>

<p>
SlickEdit is easily the most expensive text editor in this list. A single user license for one platform and one developer costs a scant 300 bucks. That is a lot of money for a text editor and is usually only shelled out only for business critical platform exclusive IDEs. It seems as if SlickEdit tries to be exactly that for general purpose text editing.
It's feature list reads very well and checks all mayor boxes. It is available on pretty much any platform out there and is probably only rivalled by Emacs or Vim in that regard. It also supports emulation for Emacs or Vim key bindings.
That said, 300-600 $ per developer is a pretty hefty price tag. Personally, I doubt that SlickEdit can live up to that price if you compare it to some of the other examples in this list. It is undoubtedly a well-maintained and powerful text editor though.
</p>
</div>
</div>

<div id="outline-container-org4d59128" class="outline-3">
<h3 id="org4d59128"><a href="http://www.activestate.com/komodo-edit">Komodo Edit</a></h3>
<div class="outline-text-3" id="text-org4d59128">

<figure id="org8470533">
<img src="http://bastibe.de/static/2012-02/komodo.png" alt="komodo.png">

</figure>

<p>
Komodo Edit is the free open source offspring of ActiveState's Komodo IDE. It's feature set is very complete and seems to be very worthy for many editing tasks. Being of IDE ancestry provides it with nice plugin support and very helpful deep language integration like sophisticated autocompletion and syntax checking.
There are also quite good Vim key bindings and it is available on the three major platforms. However, its language support is limited to Perl, Python, Tcl, PHP, Ruby and Javascript. Probably not a bad choice if you can live with the language selection and are on a budget.
</p>
</div>
</div>

<div id="outline-container-org5c50fae" class="outline-3">
<h3 id="org5c50fae">TextEdit</h3>
<div class="outline-text-3" id="text-org5c50fae">

<figure id="orge141c7c">
<img src="http://bastibe.de/static/2012-02/textedit.png" alt="textedit.png">

</figure>

<p>
The built-in text editor in OSX. No syntax highlighting, project management or any programming support whatsoever make this a rather poor choice. There are plenty of free alternatives out there.
That said, TextEdit does support rich text editing and might be of value for the odd letter to your grandma.
</p>
</div>
</div>

<div id="outline-container-org22d2c37" class="outline-3">
<h3 id="org22d2c37">Text editors for web development</h3>
<div class="outline-text-3" id="text-org22d2c37">
<p>
Strangely, all the major Mac text editors that cater specifically for web development are not cross platform. If web development is all you are ever doing though, these text editors might be well worth their money.
</p>
</div>

<div id="outline-container-org307290a" class="outline-4">
<h4 id="org307290a"><a href="http://www.panic.com/coda/">Coda</a></h4>
<div class="outline-text-4" id="text-org307290a">

<figure id="orgdf9d869">
<img src="http://bastibe.de/static/2012-02/coda.png" alt="coda.png">

</figure>

<p>
Combine the SubEthaEdit text editing engine including its collaborative tools with the great FTP program Transmit and you have CODA, the program for "one-window web development". It even includes a reference book to HTML in the package. For what it is, probably of great value and nice polish. As a general purpose text editor, there are better alternatives.
</p>
</div>
</div>

<div id="outline-container-org912acc7" class="outline-4">
<h4 id="org912acc7"><a href="http://macrabbit.com/espresso/">Espresso</a></h4>
<div class="outline-text-4" id="text-org912acc7">

<figure id="org7f5cec4">
<img src="http://bastibe.de/static/2012-02/espresso.png" alt="espresso.png">

</figure>

<p>
Another text editor gearing specifically for web development. Thus, you get powerful HTML and CSS editing features and good support for typical web development languages such as PHP, Ruby or Markdoen, but no support for other languages. There is an extension system though that could improve language support. This might be a slightly less expensive alternative to Coda.
</p>
</div>
</div>

<div id="outline-container-org17347e7" class="outline-4">
<h4 id="org17347e7"><a href="http://tacosw.com/">Taco HTML Editor</a></h4>
<div class="outline-text-4" id="text-org17347e7">

<figure id="org681df8c">
<img src="http://bastibe.de/static/2012-02/taco.png" alt="taco.png">

</figure>

<p>
Another text editor geared exclusively towards web development. This time around though, there is no support for languages other than HTML, CSS and PHP, which makes this program a rather poor choice.
</p>
</div>
</div>

<div id="outline-container-org11464b6" class="outline-4">
<h4 id="org11464b6"><a href="http://www.beforedawnsolutions.com/applications/skedit">skEdit</a></h4>
<div class="outline-text-4" id="text-org11464b6">

<figure id="org4282653">
<img src="http://bastibe.de/static/2012-02/skedit.png" alt="skedit.png">

</figure>

<p>
skEdit supports a nice array of web development languages and offers a good range of features for a web development text editor. Also, it is pretty inexpensive in comparison to its brethren here. Probably a nice choice for web development if you are on a budget.
</p>
</div>
</div>
</div>
</div>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-text-editor.html">text-editor</a> <a href="https://bastibe.de/tag-vim.html">vim</a> <a href="https://bastibe.de/tag-emacs.html">emacs</a> ]]></description>
  <category><![CDATA[text-editor]]></category>
  <category><![CDATA[vim]]></category>
  <category><![CDATA[emacs]]></category>
  <link>https://bastibe.de/2012-02-03-text-editors.html</link>
  <guid>https://bastibe.de/2012-02-03-text-editors.html</guid>
  <pubDate>Fri, 03 Feb 2012 18:22:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[How to make Tagbar work with Objective-C]]></title>
  <description><![CDATA[
<p>
For the longest time, ctags did not support Objective-C. Without tags, many of the cool programming-related features of Vim simply didn't work. (There are ways to coax other programs to output tags, but this is usually painful)
</p>

<p>
Recently however, ctags finally gained support for Objective-C! Huzzah!
As of today, Objective-C support is not in the stable branch yet, but thanks to the magic of homebrew, an Obj-C ready ctags is only a <code>brew install ctags --HEAD</code> away!
</p>

<p>
With that, tag navigation in Vim works for Objective-C. Awesome!
However, Tagbar does not work yet. There used to be <a href="http://stackoverflow.com/a/5790832/1034">a workaround</a> that apparently worked for some people, but it did not work for me.
Things like this drive me nuts. I can see that tags are being generated, but Tagbar won't show them. What is going wrong?
</p>

<p>
Some investigation proved: There is simply no template in Tagbar for Objective-C! Luckily, that can be fixed quite easily: Simply put this code in your .vimrc:
</p>

<pre class="example" id="org61221c8">
    " add a definition for Objective-C to tagbar
    let g:tagbar_type_objc = {
        \ 'ctagstype' : 'ObjectiveC',
        \ 'kinds'     : [
            \ 'i:interface',
            \ 'I:implementation',
            \ 'p:Protocol',
            \ 'm:Object_method',
            \ 'c:Class_method',
            \ 'v:Global_variable',
            \ 'F:Object field',
            \ 'f:function',
            \ 'p:property',
            \ 't:type_alias',
            \ 's:type_structure',
            \ 'e:enumeration',
            \ 'M:preprocessor_macro',
        \ ],
        \ 'sro'        : ' ',
        \ 'kind2scope' : {
            \ 'i' : 'interface',
            \ 'I' : 'implementation',
            \ 'p' : 'Protocol',
            \ 's' : 'type_structure',
            \ 'e' : 'enumeration'
        \ },
        \ 'scope2kind' : {
            \ 'interface'      : 'i',
            \ 'implementation' : 'I',
            \ 'Protocol'       : 'p',
            \ 'type_structure' : 's',
            \ 'enumeration'    : 'e'
        \ }
    \ }
</pre>

<p>
With that, Tagbar should work. Admittedly, it won't work perfectly yet. Class definitions will show up in addition to their contents and the contents of all categories will go into the same list. Also, you won't get much more than a flat list of functions with no way to distinguish between class methods and object methods. This can be confusing at times, but by and large, it does the job!
</p>


<p>
Happy Vimming!
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-vim.html">vim</a> <a href="https://bastibe.de/tag-text-editor.html">text-editor</a> ]]></description>
  <category><![CDATA[vim]]></category>
  <category><![CDATA[text-editor]]></category>
  <link>https://bastibe.de/2011-12-04-how-to-make-tagbar-work-with-objective-c.html</link>
  <guid>https://bastibe.de/2011-12-04-how-to-make-tagbar-work-with-objective-c.html</guid>
  <pubDate>Sun, 04 Dec 2011 20:21:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Compiling Scipy and Matplotlib again]]></title>
  <description><![CDATA[
<p>
Well, it's compile time again. Once again, I need to install scipy and matplotlib using homebrew and pip on Lion.
It seems things have improved since I tried to compile last time! Well, it still does not work out of the box, but at least now it can be done without compiling by hand:
(remember to <code>brew install pkg-config gfortran</code> first)
</p>

<div class="org-src-container">
<pre class="src src-sh">pip install -e git+https://github.com/scipy/scipy#egg=scipy-dev
pip install -e git+https://github.com/matplotlib/matplotlib#egg=matplotlib
</pre>
</div>

<p>
I must say, this is still a mess. But at least, it is getting less bad.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-compiling.html">compiling</a> <a href="https://bastibe.de/tag-python.html">python</a> ]]></description>
  <category><![CDATA[compiling]]></category>
  <category><![CDATA[python]]></category>
  <link>https://bastibe.de/2011-10-13-compiling-scipy-and-matplotlib-again.html</link>
  <guid>https://bastibe.de/2011-10-13-compiling-scipy-and-matplotlib-again.html</guid>
  <pubDate>Thu, 13 Oct 2011 15:27:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Adobe AIR Application Crashes]]></title>
  <description><![CDATA[
<p>
Adobe, oh Adobe. Why?
</p>

<p>
Your updater pops open. Adobe AIR 2.5, if I remember correctly. It runs, and after that, all AIR applications stop working. They boot, then crash and barf up a crash report.
</p>

<p>
Turns out, this is a problem with case sensitive file systems. If your file system is not case sensitive, you are experiencing some other problem and this fix is not for you.
</p>

<p>
See, Adobe has this library called <code>WebKit.dylib</code>. However, their code actually looks for <code>Webkit.dylib</code> (note the capitalisation of the K). Well, spelling is hard, I presume.
</p>

<p>
At least this is an error that can easily be fixed. Fire up your terminal, type
</p>

<div class="org-src-container">
<pre class="src src-sh">cd /Library/Frameworks/Adobe\ AIR.framework/Version/Current/Resources/
sudo ln -s WebKit.dylib Webkit.dylib
</pre>
</div>

<p>
Then enter your password and your AIR applications should work again.
</p>

<p>
Dear Adobe, is it too much to ask to pretty please make your software work on a case sensitive file system? Spelling is primary school stuff. It is really not that hard!
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-macos.html">macos</a> ]]></description>
  <category><![CDATA[macos]]></category>
  <link>https://bastibe.de/2011-09-03-adobe-air-application-crashes.html</link>
  <guid>https://bastibe.de/2011-09-03-adobe-air-application-crashes.html</guid>
  <pubDate>Sat, 03 Sep 2011 13:08:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Compiling Scipy and Matplotlib using pip on Lion]]></title>
  <description><![CDATA[
<p>
So I upgraded to Lion. Predictably, some things went wrong. This time, the main thing that bit me was that for some reason, <code>pip</code> stopped working. After a bit of messing around with <code>brew</code>, <code>pip</code> and <code>easy_install</code>, I found out it was almost entirely my own fault. I messed up my <code>PATH</code>.
</p>

<p>
In the meantime, I had uninstalled all of <code>brew</code>'s Python, so I had to reinstall. For me, that entails Python, Numpy, Scipy and Matplotlib. Only this time, Scipy would not build. Some obscure error in some <code>veclib_cabi_c.c</code> would report errors. A quick <a href="http://mail.scipy.org/pipermail/scipy-user/2009-June/021383.html">round of googling</a> reveals:
</p>

<p>
In order to get Scipy to compile, you need to insert <code>#include &lt;complex.h&gt;</code> in
</p>

<div class="org-src-container">
<pre class="src src-sh">    ./scipy/lib/blas/fblaswrap_veclib_c.c.src
    ./scipy/linalg/src/fblaswrap_veclib_c.c
    ./scipy/sparse/linalg/eigen/arpack/ARPACK/FWRAPPERS/veclib_cabi_c.c
</pre>
</div>

<p>
That done, Scipy compiles perfectly fine.
</p>

<p>
But, that is not enough yet. As <a href="http://jholewinski.wordpress.com/2011/07/21/installing-matplotlib-on-os-x-10-7-with-homebrew/">this blogpost</a> outlines, Matplotlib is not currently compatible with <code>libpng</code> 1.5, which ships with Lion. Fortunately, this is already fixed in the most recent source on the Matplotlib repo, so you just have to checkout that:
</p>

<div class="org-src-container">
<pre class="src src-sh">    pip install -e git+https://github.com/matplotlib/matplotlib.git#egg=matplotlib
</pre>
</div>

<p>
By doing that, Matplotlib should install just fine.
</p>

<p>
Seriously though, these PyPi repos are in a very sorry state. Every time I install one of these packages, I have to jump through hoops and spend hours debugging packages that really should work right out of the box. After all, <code>brew</code>, <code>rvm</code> and <code>gem</code> can do it just fine. Why is <code>pip</code> such a horrible mess?
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-compiling.html">compiling</a> <a href="https://bastibe.de/tag-python.html">python</a> <a href="https://bastibe.de/tag-macos.html">macos</a> ]]></description>
  <category><![CDATA[compiling]]></category>
  <category><![CDATA[python]]></category>
  <category><![CDATA[macos]]></category>
  <link>https://bastibe.de/2011-08-01-compiling-scipy-and-matplotlib-using-pip-on-lion.html</link>
  <guid>https://bastibe.de/2011-08-01-compiling-scipy-and-matplotlib-using-pip-on-lion.html</guid>
  <pubDate>Mon, 01 Aug 2011 12:40:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Installing Pygame using Homebrew]]></title>
  <description><![CDATA[
<p>
So I want to do audio development on the Mac without using Matlab. An alternative to Matlab is Python, or rather, <a href="http://www.daskrachen.com/2011/02/installing-pythonnumpyscipymatplotlib.html">Numpy, Scipy and Matplotlib</a>. They are awesome for working with audio data. What they don't do however is playing back audio. There are several packages out there that would afford audio playback. If you are serious about this though, you not only want audio playback, you want asynchronous audio playback. That is, you want to send some audio data to the sound card and continue with your program without waiting for the audio to finish playing. This allows continuous audio playback of computer-generated sound.
</p>

<p>
<a href="http://www.pygame.org/news.html">Pygame</a> is one package that allows this. (I will submit a patch to <a href="http://people.csail.mit.edu/hubert/pyaudio/">Pyaudio</a> soon that will enable it there, too). There are pre-built binaries on the Pygame website that you can install easily. But then there would be no easy way to uninstall them, so what I would rather want is to install Pygame using package managers that allow easy updating and uninstallation. My tool of choice on the Mac is of course <a href="https://github.com/mxcl/homebrew/">Homebrew</a>.
</p>

<p>
Note that although I am mostly interested in audio playback, this post will detail the installation of all modules of Pygame, not just <code>pygame.mixer</code>.
</p>

<p>
Homebrew won't install Pygame, but it will install all the prerequisites for Pygame. So, let's do that.
</p>

<div class="org-src-container">
<pre class="src src-sh">brew install sdl, sdl_mixer, sdl_ttf, libpng, jpeg, sdl_image, portmidi
</pre>
</div>

<p>
This will install most packages for you. Note that <code>libpng</code> is also available as a system library, so it is installed <code>keg_only</code>, that is, without linking it in your path. We will need to compile against it though, so the next step is
</p>

<div class="org-src-container">
<pre class="src src-sh">brew link libpng
</pre>
</div>

<p>
Now there is still one package missing, <code>smpeg</code>. Sadly, <code>smpeg</code> does not install its headers, so you can't compile against it. To fix that, type
</p>

<div class="org-src-container">
<pre class="src src-sh">brew edit smpeg
</pre>
</div>

<p>
and add the following line just above the two end at the end of the file
</p>

<div class="org-src-container">
<pre class="src src-sh">include.install Dir["*.h"]
</pre>
</div>

<p>
Then save the file. (I submitted a bug to have this fixed, so you might not need to do this when you read this). Now you can install <code>smpeg</code> with the usual
</p>

<div class="org-src-container">
<pre class="src src-sh">brew install smpeg
</pre>
</div>

<p>
and you will get the headers, too. Isn't Homebrew great?
</p>

<p>
Now that all the prerequisites are met, lets look at Pygame itself. This is rather more difficult, as it will not build properly against Homebrew libraries on its own. First, download the source package of Pygame from the [official website](<a href="http://www.pygame.org/download.shtml">http://www.pygame.org/download.shtml</a>). Unpack it to some directory.
</p>

<p>
Now open a terminal and navigate to that directory. Me, I like [iTerm](<a href="http://iterm.sourceforge.net/">http://iterm.sourceforge.net/</a>), but Terminal.app will do just fine, too. In there, run <code>python config.py</code> to create an initial setup file.
</p>

<p>
At this point, the setup file is mostly useless since <code>config.py</code> failed to find any homebrew-installed library. It is also strangely garbled, so there is some manual labor to do. Open the file <code>Setup</code> (no extension) in your favourite text editor. After the first comment block, you will see a line that looks like this
</p>

<div class="org-src-container">
<pre class="src src-sh">SDL = -I/NEED_INC_PATH_FIX -L/NEED_LIB_PATH_FIX -lSDL
</pre>
</div>

<p>
Obviously, this is lacking the paths to the SDL library. If you installed Homebrew to its default directory, this will be in <code>/usr/local…</code>. Hence, change this line to
</p>

<div class="org-src-container">
<pre class="src src-sh">SDL = -I/usr/local/include/SDL -L/usr/local/lib -lSDL
</pre>
</div>

<p>
The next lines are strangely garbled. They say, for example
</p>

<div class="org-src-container">
<pre class="src src-sh">FONT = -lS -lD -lL -l_ -lt -lt -lf
</pre>
</div>

<p>
Where they actually should say
</p>

<div class="org-src-container">
<pre class="src src-sh">FONT = -lSDL_ttf
</pre>
</div>

<p>
Instead of having one <code>-l</code> and then the library name <code>SDL_ttf</code>, they put <code>-l</code> in front of every single letter of the name. This is strange, and certainly wrong. So, correct it for <code>FONT</code>, <code>IMAGE</code>, <code>MIXER</code> and <code>SMPEG</code>.
</p>

<p>
Note that I did not tell you to do this for <code>PORTTIME</code>, too. Actually, <code>PORTTIME</code> is already correctly linked in <code>PORTMIDI</code>, so you don't need that at all any more. Just delete or comment the <code>PORTTIME</code> line.
</p>

<p>
Now that all the dependencies are corrected, lets enable the features. A few lines further down, there will be a block of lines, where most lines begin with a <code>#</code> except for the ones beginning with <code>_numericsurfarray…</code> and <code>_camera…</code>, These are the different features of Pygame: The ones with the <code>#</code> are disabled, the other two are enabled.
</p>

<p>
With all the stuff we installed earlier, you can now enable all features (remove the <code>#</code> in front of <code>imageext…</code>, <code>font…</code>, <code>mixer…</code>, <code>mixer_music…</code>, <code>_minericsndarray…</code>, <code>movie…</code>, <code>scrap…</code> and <code>pypm…</code>).
</p>

<p>
Remember we disabled <code>PORTTIME</code> a while ago? Right, so we have to remove that dependency: In the line starting with <code>pypm…</code>, delete the part that says <code>$(PORTTIME)</code>. Great. That was easy, right? Now save that file and go back to the Terminal.
</p>

<p>
We are now going to compile and install Pygame. The nice thing is, even though we are installing it manually, it will go in the right directories and it will be registered with <code>pip</code> or <code>easy_install</code>, so you can just invoke them if you want to uninstall it later by typing <code>pip uninstall pygame</code>. This is something I love about Python!
</p>

<p>
Alright, now without further ado, install Pygame by typing
</p>

<div class="org-src-container">
<pre class="src src-sh">python setup.py install
</pre>
</div>

<p>
Great! That's it! Everything should work now!
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-compiling.html">compiling</a> <a href="https://bastibe.de/tag-python.html">python</a> <a href="https://bastibe.de/tag-macos.html">macos</a> ]]></description>
  <category><![CDATA[compiling]]></category>
  <category><![CDATA[python]]></category>
  <category><![CDATA[macos]]></category>
  <link>https://bastibe.de/2011-03-04-installing-pygame-using-homebrew.html</link>
  <guid>https://bastibe.de/2011-03-04-installing-pygame-using-homebrew.html</guid>
  <pubDate>Fri, 04 Mar 2011 14:16:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Installing Python/Numpy/Scipy/Matplotlib on OSX]]></title>
  <description><![CDATA[
<p>
For numerical analysis and signal processing prototyping, you would use <a href="http://www.mathworks.com/products/matlab/">Matlab</a>. However, Matlab has some downsides that might make it unsuitable for your project. It might be too expensive. You might be a snobbish programmer that can't stand less-than-elegant programming languages. I certainly am.
</p>

<p>
So, you look for alternatives. You could take <a href="http://www.gnu.org/software/octave/">Octave</a>, which is free, but that would not solve that ugly-code issue. You could take any scripting language you fancy, but Ruby, Perl and Python are too slow to do serious number crunching.
</p>

<p>
Then, you stumble upon that Python package called <a href="http://numpy.scipy.org/">Numpy</a>, which seems to be nearly as fast as Matlab when it comes to matrix processing and linear algebra. You then discover <a href="http://www.scipy.org/">SciPy</a>, which would add all that signal processing prowess of Matlab (do quick transformations, random numbers, statistics) to your toolbox. Last but not least, you need plotting. That would be <a href="http://matplotlib.sourceforge.net/">Matplotlib</a> then, which provides quick plotting facilities in Python.
</p>

<p>
And the best thing is, these three systems work really well together. They seem to be the perfect replacement for Matlab that could even be superiour to it in many regards.
</p>

<p>
Next up, you need to install all that stuff. If you are like me, you naturally want to do all that on a Mac. Also, you kind of dislike all these installer-thingies, which install stuff to unknown places and are nigh impossible to uninstall or update cleanly. Even though, you could of course just go to the individual websites, download Python, Numpy, SciPy and Matplotlib, run them installers, and be done. You would save yourself a lot of trouble that way.
</p>

<p>
But since you allegedly are like me, you instead fire up <a href="http://mxcl.github.com/homebrew"><code>brew</code></a> and try to install all that stuff using that. Again, you could use <a href="http://www.macports.org/">MacPorts</a> or <a href="http://www.finkproject.org/">Fink</a> instead, but you probably had some bad experiences with them and you generally love the hackishness of Homebrew, so this is your natural first try.
</p>

<p>
So you set about this, you believe in packet managers and trust them to take care of every obstacle that might be lying in your way. First of all, install the latest developer tools from <a href="http://developer.apple.com/">developer.apple.com</a>. You might need to register (for free) to get them. Also, you need to install <a href="http://mxcl.github.com/homebrew">Homebrew</a>.
</p>

<p>
To cut this short, here is what you need to get that Python running:
</p>

<div class="org-src-container">
<pre class="src src-sh">    brew install python
</pre>
</div>

<p>
This one should be obvious. At the time of writing, it will install Python 2.7.1. You could take Python 3, but matplotlib is not compatible to it, so you kind of have to stick with 2.7.1 instead.
</p>

<p>
You also need to put <code>/usr/local/bin</code> and <code>/usr/local/sbin</code> in the beginning of your path to make sure the new Python gets loaded instead of the pre-installed one. You do that by writing
</p>

<div class="org-src-container">
<pre class="src src-sh">    export PATH=/usr/local/bin:/usr/local/sbin:$PATH
</pre>
</div>

<p>
in your <code>\~/.bash_profile</code>. (Create it if its not there&#x2013;it is just a simple text file).
</p>

<p>
Now, if you type <code>python --version</code>, you should get <code>Python 2.7.1</code> as a response.
</p>

<p>
Alright, next up, install the python package manager:
</p>

<div class="org-src-container">
<pre class="src src-sh">    brew install distribute
    brew install pip
</pre>
</div>

<p>
This will come preconfigured for your newly installed Python. In an ideal world, this should be all. The world being as it is, the pip package of Matplotlib is severely broken and has one other unstated dependency:
</p>

<div class="org-src-container">
<pre class="src src-sh">    brew install pkg-config
</pre>
</div>

<p>
Also, SciPy is using some FORTRAN sources, so you need a fortran compiler:
</p>

<div class="org-src-container">
<pre class="src src-sh">    brew install gfortran
</pre>
</div>

<p>
Alright. That was enough. Now on to pip. With all these dependencies cleared, pip should be able to download Numpy and Scipy without trouble:
</p>

<div class="org-src-container">
<pre class="src src-sh">    pip install numpy
    pip install scipy
</pre>
</div>

<p>
Matplotlib, on the other hand, is more difficult to install. You see, pip is looking at the Python package repository <a href="http://pypi.python.org/">PyPi</a> for each package. PyPi then provides a URL. Pip then scans that website for links to suitable package files. But, <a href="http://sourceforge.net/">Sourceforge</a> changed its links a while ago, so pip gets confused and will download an outdated version. Sourceforge says, its new links are way better and no way we will change them back; Pip says, well, if Sourceforge can't provide proper links, that's not our problem. Oh My. Silly children.
</p>

<p>
So we have to do this manually:
</p>

<div class="org-src-container">
<pre class="src src-sh">    pip install -f http://sourceforge.net/projects/matplotlib/files/matplotlib/matplotlib-1.0.1/matplotlib-1.0.1.tar.gz matplotlib
</pre>
</div>

<p>
That URL comes straight from Sourceforge. Look for the latest version of Matplotlib, search for the download link to the source distribution (<code>*.tar.gz</code>), copy that link and strip any trailing '/download'.
</p>

<p>
UPDATE:
</p>

<p>
It seems the matplotlib package was updated in the meantime, so you can just run <code>pip install matplotlib</code> now.
</p>

<p>
This should now download and install matplotlib.
</p>

<p>
Thank you for reading.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-compiling.html">compiling</a> <a href="https://bastibe.de/tag-python.html">python</a> <a href="https://bastibe.de/tag-macos.html">macos</a> ]]></description>
  <category><![CDATA[compiling]]></category>
  <category><![CDATA[python]]></category>
  <category><![CDATA[macos]]></category>
  <link>https://bastibe.de/2011-02-03-installing-python-slash-numpy-slash-scipy-slash-matplotlib-on-osx.html</link>
  <guid>https://bastibe.de/2011-02-03-installing-python-slash-numpy-slash-scipy-slash-matplotlib-on-osx.html</guid>
  <pubDate>Thu, 03 Feb 2011 16:23:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[The strangeness of widescreen displays in modern operating systems]]></title>
  <description><![CDATA[
<p>
So today, pretty much everyone has widescreen displays. That is, displays that are far more wide than high. This was not always so. In ye olden days, computers were mainly used for displaying text, hence displays tended to have a similar layout as books or magazines. Today, they are more like movies (which might be worrying in itself).
</p>


<figure id="org66cbf2e">
<img src="http://bastibe.de/static/2010-03/aspect_ratios.png" alt="aspect_ratios.png">

</figure>

<p>
So todays displays are widescreen. To do all that modern stuff, like watch (widesreened) videos or multitask (display two windows side by side). However, this also means that vertical pixels are something of a scarcity. Especially on those small Laptop screens. In fact, the first Netbook screens were so tiny that many of Windows' own windows could not be used at all since the lower parts did not fit on the screen. Raise your hand if Word 2007 leaves barely ten lines of visible text between all its blue-tinted UI-splendour on your laptop screen.
</p>


<figure id="orgeeeb7b7">
<img src="http://bastibe.de/static/2010-03/word_small.png" alt="word_small.png">

</figure>

<p>
This gets most straining when reading text. On the internet for example. There is practically no website at all that can be displayed in its entirity even on one of those full HD displays. Print-formatted documents are a similar matter. Actually, I find myself craving for pixels regularly. I even disable the bookmark bar in my browser to free those extra two lines of text. And I memorize keyboard shortcuts so I can hide toolbars. And I use Google Chrome instead of Firefox/Safari/Internet Explorer, not least of all since it has the smallest title bar and no bottom bar.
</p>

<p>
Why, then, do modern operating systems still waste so much vertical space with that Dock/Taskbar? This is something I really don't get. Vertical space is such a scarcity, yet virtually every operating system choses to waste at least three lines of text with something that could easily go on the side of the display. Well, at least on Windows 7 and OSX that is something you can easily change.
</p>


<figure id="org3e1fc5b">
<img src="http://bastibe.de/static/2010-03/dock_small.png" alt="dock_small.png">

</figure>

<p>
So if you are like me and appreciate every added line of text, do yourself a favour and put your Dock/Taskbar on the side. Really, this should be the default.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-ui.html">ui</a> ]]></description>
  <category><![CDATA[ui]]></category>
  <link>https://bastibe.de/2010-07-03-strangeness-of-widescreen-displays-in-modern-operating-systems.html</link>
  <guid>https://bastibe.de/2010-07-03-strangeness-of-widescreen-displays-in-modern-operating-systems.html</guid>
  <pubDate>Sat, 03 Jul 2010 12:08:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Gedanken zu User Interfaces]]></title>
  <description><![CDATA[
<p>
Jeder kennt dieses Fenster:
</p>


<figure id="org8fb4668">
<img src="http://bastibe.de/static/2009-04/delete_file.png" alt="delete_file.png">

</figure>

<p>
Dieses Fenster ist eine ziemlich schlechte Idee, denn jeder geübte Benutzer hat irgendwann gelernt, dass die Aktion "Dateien Löschen" aus drei Gesten besteht: (1) Dateien auswählen, (2) Die Löschaktion einleiten, (3) Den Löschdialog bestätigen. Leider hat man schon vor mehr als zwanzig Jahren nachgewiesen, dass solche zusammengehörigen Gesten von den Benutzern als einzelne "Datei-Löschen" Geste abstrahiert werden. Man kennt das vom Tippen: Man tippt Worte nicht, indem man einzelne Buchstaben aneinander hängt, sondern man tippt Worte fast immer am Stück; Hat man erst einmal angefangen, ein falsches Wort zu tippen, kann man damit nicht aufhören, bis das gesamte Wort getippt ist. Auf ähnliche Weise ist es dem Benutzer auch nicht möglich, auf den Löschdialog sinnvoll zu reagieren, da das Bestätigen der Sicherheitsfrage vollkommen automatisiert ist und daher nicht einmal verhindert werden könnte, wenn man wollte.
Die Alternative ist ein alter Bekannter: Undo. Statt den Benutzer im Vorfeld zu fragen, ob er die Datei wirklich löschen möchte (was er durch Einleiten der Löschaktion bereits bejaht hat) gibt man ihm die Möglichkeit, die Aktion im Nachhinein wieder rückgängig zu machen. Das ist wesentlich effektiver und kommt ohne nerviger Dialogbox aus. Übrigens funktioniert Dateiaktion-Undo bereits heute in allen Betriebssystem außer Linux, jedoch ohne Menüicon und zumeist nur für die letzte Aktion. Wäre es nicht schön, wenn dies noch weiter ausgebaut würde?
</p>

<p>
Noch ein gefährlicher Dialog:
</p>


<figure id="orge374b19">
<img src="http://bastibe.de/static/2009-04/ja_nein_abbrechen.png" alt="ja_nein_abbrechen.png">

</figure>

<p>
Das ist ebenfalls ein alter Bekannter, der immer dann erscheint, wenn man ein Programm schließen will, welches noch ungesichte Änderungen enthält: Abgesehen von dem offensichtlichen Problem, dass "Abbrechen" keinen wirklichen Sinn ergibt (Was abbrechen? Das Programm?) erfordert diese Frage jedes Mal das komplette Lesen der Meldung, bis man entschlüsseln kann, was "Ja" und "Nein" in diesem Kontext bedeuten. Um das noch einmal zu verdeutlichen, hier ein besonders schlimmes Beispiel:
</p>


<figure id="org0b88bd6">
<img src="http://bastibe.de/static/2009-04/bad_gui.png" alt="bad_gui.png">

</figure>

<p>
Es leuchtet ein, dass hier ein eindeutigerer Dialog wesentlich sinnvoller wäre, bei dem sofort ersichtlich ist, was welcher Button tun wird: (Merke: Auf Buttons gehören immer Verben)
</p>

<p>
<img src="http://bastibe.de/static/2009-04/speichern_windows.png" alt="speichern_windows.png">]]
<img src="http://bastibe.de/static/2009-04/speichern_mac.png" alt="speichern_mac.png">
</p>

<p>
Aber warum eigentlich überhaupt speichern? Warum muss ich mich persönlich darum kümmern, meine Arbeit zu speichern? Ich dachte, ich würde mit einer Datei arbeiten &#x2013; aber wenn diese Datei nicht geändert wird, wenn ich nicht zuerst "Speichern" anklicke, habe ich wohl eigentlich doch nicht mit dieser Datei, sondern mit einer heimlichen Kopie gearbeitet. Wäre es nicht viel sinnvoller, immer automatisch zu speichern, und statt des "Speichern"-Buttons eine "auf Urzustand zurücksetzen"-Funktion bereitzustellen? Ich bin mir auf jeden Fall sicher, dass man den "Undo all changes"-Button wesentlich seltener bräuchte als den "Speichern"-Button, denn wenn der Benutzer nicht vorgehabt hätte, neuen Text in eine Datei zu schreiben, dann hätte er keinen neuen Text in die Datei geschrieben. Hat er dennoch "versehentlich" Text eingegeben, ist das ein klarer "Benutzerfehler", also der logische Einsatzzweck für Undo.
</p>

<p>
Das sind nur zwei Beispiele, wie man intelligente Undo-Mechanismen sinnvoll einsetzen könnte, um das Arbeiten am Computer angenehmer zu gestalten. Ich wünschte, mehr Leute würden sich mit diesen Dingen auseinander setzen&#x2026;
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-ui.html">ui</a> ]]></description>
  <category><![CDATA[ui]]></category>
  <link>https://bastibe.de/2009-04-25-gedanken-zu-user-interfaces.html</link>
  <guid>https://bastibe.de/2009-04-25-gedanken-zu-user-interfaces.html</guid>
  <pubDate>Sat, 25 Apr 2009 14:15:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Tagged File System]]></title>
  <description><![CDATA[
<p>
Ein großes Problem bei der Benutzung von Computern ist, dass unerfahrene Benutzer oftmals kein Verständnis für Ordnerstrukturen haben. Das ist im Grunde auch klar, denn die Ordner-Metapher legt nahe, dass sich Ordner auf dem Computer wie echte Aktenordner verhalten, also dass jeder Ordner mehrere Dateien, jedoch nicht andere Ordner enthalten kann. Ganz im Gegenteil dazu basiert aber eine normale Verzeichnisstruktur meist aus vielen, tief ineinander geschachtelten Ordnern. Von einem Usablitity-Standpunkt aus ist daher der Begriff "Ordner" wahrscheinlich schlecht gewählt. Vielleicht würde es schon reichen, den älteren Namen "Verzeichnis" wieder einzuführen. (Dann bräuchten wir nur noch ein passendes Piktogramm für "Verzeichnis"&#x2026;)
</p>


<figure id="orge167c9e">
<img src="http://bastibe.de/static/2009-04/standard_finder_small.png" alt="standard_finder_small.png">

</figure>

<p>
Es wäre daher wünschenswert, eine einfacher zu verstehende Alternative zu Ordnerhierarchien zu haben. Die gibt es auch schon, in Form der bekannten Verzeichnisse "Meine Bilder", "Meine Dokumente", etc.
Diese Ordner wollen den Benutzer mit einfachen Piktogrammen und klaren Namen dazu animieren, einen natürlichen Ort für seine Dateien zu wählen und so ein wenig Ordnung zu schaffen. Tatsächlich ist dieses Konzept einer Tag-Struktur schon relativ ähnlich, da auch hier nicht davon ausgegangen wird, dass sich der Benutzer selbst um eine tief geschachtelte Orderhierarchie kümmert, sondern nur wenige, einfach zu verstehende Markierungsmöglichkeiten ("Bilder", "Dokumente") geboten werden.
</p>

<p>
Ein echtes Tag-basiertes System könnte vollkommen ohne Verzeichnisse auskommen, wobei man dann eben beim Speichern einer Datei nicht mehr aus einer hierarchischen Liste von Ordnern den Speicherort auswählen würde, sondern von einer flachen Liste von Tags. Die Usability-Kosten davon wären vernachlässigbar.
</p>


<figure id="orgd876086">
<img src="http://bastibe.de/static/2009-04/tagged_finder_small.png" alt="tagged_finder_small.png">

</figure>

<p>
Ähnlich würde das Finden von Dateien funktionieren: Statt eine hierarchische Liste von Ordnern nacheinander anzuklicken, würde man eine flache Liste von Tags nacheinander anklicken, jedoch mit dem Bonus, dass man die gesuchte Datei nicht erst bei Anklicken aller Tags, sondern mit großer Wahrscheinlichkeit schon nach ein oder zwei Tags gefunden hätte.
</p>

<p>
Ein Problem würde jedoch mit Projekten entstehen, die aus mehreren Dateien bestehen. Hier müsste man sicher stellen, dass sie im Dateisystem nur als einzelne große Projektdatei auftauchen und nicht jede einzelne Unterdatei gelistet wird. Das ließe sich zum Beispiel durch "Bundles" lösen, wie sie heute schon in OSX vorkommen (Ordner mit definierter Namesendung und Inhalt werden wie Dateien behandelt) oder einfach durch einen speziellen Tag, der die einzelnen Dateien vor der normalen Suche versteckt.
Dieses Konzept wird übrigens heute schon vielfach verwendet, so ist etwa eine aktuelle Word-Datei nur eine ZIP-Datei, die eine definierte Verzeichnisstruktur mit allen Bildern, dem Text (als XML), einer Vorschau-Grafik etc. enthält.
</p>


<figure id="orgafcbc06">
<img src="http://bastibe.de/static/2009-04/bundles_small.png" alt="bundles_small.png">

</figure>

<p>
Ich glaube, dass man mit solch einem Tag-basierten Dateisystem deutlich einfacher arbeiten könnte als mit den heute üblichen Verzeichnisstrukturen. Tja, jetzt fehlt nur noch eine innovative Firma, die sich um die Umsetzung kümmert&#x2026;
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-ui.html">ui</a> ]]></description>
  <category><![CDATA[ui]]></category>
  <link>https://bastibe.de/2009-04-19-tagged-file-system.html</link>
  <guid>https://bastibe.de/2009-04-19-tagged-file-system.html</guid>
  <pubDate>Sun, 19 Apr 2009 09:41:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Es geht um Tabs]]></title>
  <description><![CDATA[
<p>
Tabs sind kaputt. Tabs waren noch nie eine gute Idee. Tabs werden dafür benutzt, um in einem Programm mehrere Fensterflächen voll Inhalt in nur einem Fenster darzustellen. Speziell zu diesem Zweck entwarf man in grauer Vorzeit eine neue Klasse von Programmen namens Fenstermanager. Fenstermanager erlauben es, mehrere Fenster gleichzeitig darzustellen, gerne auch nebeneinander, hintereinander oder übereinander. Kennt jeder. Und Tabs sind eine Krücke, die genau dieses Prinzip unterlaufen, denn sie organisieren Fenster ineinander.
</p>

<p>
Aber es ist ja nicht nur das. Wir kennen Tabs schon lange in ganz verschiedenen Formen:
</p>

<p>
<img src="http://bastibe.de/static/2009-03/tabs_firefox_preferences.png" alt="tabs_firefox_preferences.png">
<img src="http://bastibe.de/static/2009-03/tabs_osx.png" alt="tabs_osx.png">
<img src="http://bastibe.de/static/2009-03/tabs_windows.png" alt="tabs_windows.png">
</p>

<p>
All diesen Formen gemein ist, dass sie wenigstens einen Rahmen bilden, der andeutet, welcher Teil des Fensters sich ändern wird, wenn man einen anderen Tab öffnet. Die Ausnahme: Browser.
</p>

<p>
<img src="http://bastibe.de/static/2009-03/tabs_ie8.png" alt="tabs_ie8.png">
<img src="http://bastibe.de/static/2009-03/tabs_firefox.png" alt="tabs_firefox.png">
</p>

<p>
Wo hat ein Browser seine Tabs? zwischen Adressleiste und Webseiteninhalt. Bei Firefox (besondere Perversion) sind die Tabs sogar so dargestellt, als würden sie nur die Adresszeile ändern (oben befestigte Reiter), ganz im Gegensatz dazu ändern sie aber sowohl die Adresszeile als auch -viel wichtiger- den Webseiteninhalt. Wenn überhaupt, dann sollten sich die Tabs also am oberen Bildschirmrand befinden, so dass man mit ihnen wenigstens konsistent den kompletten Fensterinhalt ändert. Immerhin hier sieht man bereits Licht: Google Chrome und Safari 4 funktionieren bereits so:
</p>

<p>
<img src="http://bastibe.de/static/2009-03/tabs_chrome.png" alt="tabs_chrome.png">
<img src="http://bastibe.de/static/2009-03/tabs_safari_windows.png" alt="tabs_safari_windows.png">
<img src="http://bastibe.de/static/2009-03/tabs_safari_osx.png" alt="tabs_safari_osx.png">
</p>

<p>
Die Lösung von Safari hat noch ein paar Probleme: Wo verschiebt man Tabs? (Ungeschickt: an dem kleinen Handle am rechten Tabgreifer-Rand), Wieso haben die Tabs keine Favicons? Aber nicht verzagen: Noch ist Safari 4 lediglich eine Beta. Gut hingegen fände ich es, wenn dieses Tabbed-Fenster-Interface nicht nur für Safari, sondern für jedes andere Programm auch verwendbar wäre, also als Feature des Fenstermanagers implementiert würde. Man müsste daran noch ein wenig feilen, aber es würde Einiges sehr viel übersichtlicher gestalten. Snow Leopard anyone?
</p>

<p>
Weitere gute Ideen rund um Tabs, sortiert nach Browser:
</p>

<ul class="org-ul">
<li><p>
<a href="http://www.microsoft.com/windows/internet-explorer/default.aspx">Microsoft Internet Explorer 8</a>
</p>
<ul class="org-ul">
<li>Tabs werden nach Farben sortiert, je nach dem von welchem Tab aus sie geöffnet wurden</li>
<li>Im neuen Fenstermanager von Windows 7 werden alle Tabs als eigene Fenster aufgeführt</li>
<li>Jeder Tab läuft in seinem eigenen Prozess. Bringt aber nix, weil wenn einer abstürzt nimmt er trotzdem den ganzen Browser mit. Ist aber auch noch nur Beta!</li>
</ul>

<figure id="org3c86390">
<img src="http://bastibe.de/static/2009-03/tabs_ie8_goodness_small.png" alt="tabs_ie8_goodness_small.png">

</figure></li>
<li><a href="http://www.mozilla-europe.org/de/firefox/">Firefox 3</a> Preview
<ul class="org-ul">
<li>Tabs sollen über ein neuartiges Interface beim Wechsel als Miniaturen dargestellt werden, so dass man einfacher zwischen ihnen wechseln kann</li>
<li>Viele andere nette Vorschläge rund um diese Idee gibts hier: <a href="http://www.azarask.in/blog/post/new-tab-iterations/">Aza Raskins Blog</a></li>
</ul></li>
<li><a href="http://www.apple.com/safari/">Safari 4</a>
<ul class="org-ul">
<li>Die Tableiste nimmt keinen eigenen Platz auf dem Bildschirm ein</li>
<li>Tabs sind am richtigen Ort (oben)</li>
</ul></li>
<li><p>
<a href="http://www.google.com/chrome">Google Chrome</a>
</p>
<ul class="org-ul">
<li>Tabs sind am richtigen Ort (oben) aber es gibt dennoch eine klassische Titelleiste des Fensters (im Gegensatz zu Safari 4)</li>
<li>Jeder Tab läuft in einem eigenen Prozess, daher können einzelne Tabs abstürzen ohne den Browser mitzunehmen.</li>
<li>Jeder Tab läuft in seiner eigenen Sandbox, was es Angreifern wesentlich erschwert, den Browser hochzunehmen.</li>
</ul>

<figure id="org78eb820">
<img src="http://bastibe.de/static/2009-03/tabs_chrome_goodness.png" alt="tabs_chrome_goodness.png">

</figure></li>
</ul>

<p>
Fazit: Es gibt noch viel zu tun, aber anscheinend ergibt sich langsam aber sicher ein Konsens, dass etwas mit Tabs getan werden muss. Es bleibt spannend.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-ui.html">ui</a> ]]></description>
  <category><![CDATA[ui]]></category>
  <link>https://bastibe.de/2009-03-31-es-geht-um-tabs.html</link>
  <guid>https://bastibe.de/2009-03-31-es-geht-um-tabs.html</guid>
  <pubDate>Tue, 31 Mar 2009 20:09:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Mirrors Edge]]></title>
  <description><![CDATA[

<figure id="org44e833a">
<img src="static/2009-03/mirrors_edge.png" alt="mirrors_edge.png">

</figure>

<p>
Ich habe am Wochenende, wie in Twitter schon verkündet, Mirror’s Edge (durch-) gespielt. Ganz kurz: Mirror’s Edge ist ein Videospiel für PC/XBOX360/PS3, im Endeffekt ein Platformer aus der Ego-Perspektive, zwar mit der Möglichkeit, Waffen aufzunehmen, aber mit dem klaren Fokus auf Rennen, genauer: Parkours, dem modernen Hindernislauf, hier mit dem Extratwist: auf Hochhausdächern.
</p>

<p>
Es wurde schon viel gesagt über dieses Spiel. Müde Story, schlechte Charactermodelle, schlechte Shooter-Elemente, unübersichtliche Atmosphäre, kurze Spieldauer, um nur einige der üblichen Kritikpunkte zu nennen.
</p>


<figure id="org08948de">
<img src="static/2009-03/mirrors_edge_jump.png" alt="mirrors_edge_jump.png">

</figure>

<p>
Ich sage: Alles Popauswurf. Was Mirror’s Edge versucht, ist die Direktheit und Intimität der Egoperspektive mit dem Flow und der Geschwindigkeit eines modernen Platformers zu verbinden. Faith, der Hauptcharakter ist eine kleine “Eurasierin” (Zitat der Entwickler), deren Eltern in einem Widerstandskampf… Bla, bla, bla.
Es geht um Flow, es geht darum, mit blitzschnellen Reflexen und akrobatischem Geschick einen Weg über die Dächer einer Großstadt zu finden. Es geht darum, nicht stehen zu bleiben, nicht zu zögern. Es geht um Geschwindigkeit und Freiheit, über Straßenschluchten zu springen, zwischen Klimaanlagen und Baugerüsten zu sprinten und immer schneller, immer weiter, den Großstadtlärm hinter sich zu lassen. Nur begleitet von Faiths immer wieder ins Bild ragenden Armen und Beinen, ihrem schnellen Atem, dem Rhythmus ihrer Schritte. Und ja, man stirbt häufig, wenn man sich bei einem Sprung verschätzt oder es doch nicht schafft, den Jägern zu entkommen. Aber um so größer ist die Befriedigung einen komplizierten Run endlich zu schaffen und mit einem perfekten Sprung über eine Häuserschlucht die Polizei hinter sich zu lassen.
</p>

<p>
Mirror’s Edge perfektioniert den Flow, das Gefühl der Freiheit und der Geschwindigkeit. Klar, dass da die Ego-Shooter-Mechanik auf der Strecke bleibt, aber Faith ist auch keine Kämpferin, sondern selbsterklärter Runner. Sicher, die Story ist ein wenig lahm, aber wir reden hier über ein Computerspiel: Die Story hat allein das Ziel, die einzelnen Schauplätze miteinander zu verbinden, und das gelingt ihr. Charakterentwicklung kennt das Spiel nicht, allein der Spieler wird besser. Und auch das ist gut so, denn in den späteren Leveln ist der Schwierigkeitsgrad nicht von schlechten Eltern. Aber Checkpoints sind häufig und fair verteilt, so dass dies selten ein Problem wird.
</p>

<p>
Ach ja, und der Sound ist genial, selten habe ich mich so sehr in eine Spielfigur hineinversetzt gefühlt wie in Faith. Und die Grafik… Ich könnte hier viel schreiben; Ich glaube schlicht, dass die aktuelle Konsolengeneration im Grunde ein Niveau erreicht hat, auf dem weitere Verbesserungen keine große Rolle mehr spielen. Mirror’s Edge, mit seiner gleißend-Weiß-plus-Farbe Ästhetik zeigt hier eine Welt, wie man sie noch nie gesehen hat, in der Farbe nicht nur als Stilmittel, sondern auch als Wegweiser und tatsächlich Spielhilfe eingesetzt wird: Rot ist, wo es weiter geht. Diese Ästhetik ist schwer in Worte zu fassen und gibt dem Ganzen eine ganz eigene Freiheit, im starken Kontrast zum “realistisch”-Grau-Braun, dem sich so viele andere Spiele verschrieben haben.
</p>

<p>
Und was bleibt unterm Strich? Ich sage: Das Spiel ist es Wert. Es mag seine Mängel haben, aber allein der Mut, einmal etwas Neues zu machen und nicht dem Einheitsbrei ins Land der Realo-Shooter und der digitalen Nebenjobs zu folgen ist der Beachtung Wert. Einmal nicht schießen zu müssen und stumpfen Missionen zu folgen, sondern in einem Spiel Freiheit zu finden, dass ist eine außergewöhnliche Erfahrung. Wer als Spieler etwas Erfrischung sucht, sollte es probieren. Ich finds geil!
</p>


<figure id="orgbe2198e">
<img src="static/2009-03/mirrors_edge_faith.png" alt="mirrors_edge_faith.png">

</figure>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-games.html">games</a> ]]></description>
  <category><![CDATA[games]]></category>
  <link>https://bastibe.de/2009-03-29-mirrors-edge.html</link>
  <guid>https://bastibe.de/2009-03-29-mirrors-edge.html</guid>
  <pubDate>Sun, 29 Mar 2009 22:22:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Synchronisieren von Google, Äpfeln, Fenstern und Telefonen]]></title>
  <description><![CDATA[

<figure id="orgc2cc4d3">
<img src="http://bastibe.de/static/2009-03/cloud.jpg" alt="cloud.jpg">

</figure>

<p>
Ich hatte lange Zeit zwei Computer, einen Desktop und einen Laptop, jeweils mit verschiedenen Betriebssystemen und Datensätzen. Um dennoch immer mit den selben Daten arbeiten zu können, verwendete ich eine externe Festplatte. Obwohl sehr low-tech, funktionierte diese Lösung absolut tadellos: Meine Linux-Kisten mounteten die Festplatte automatisch in ihr jeweiliges home-Verzeichnis und so konnte ich auf verschiedenen Computern arbeiten, ohne mich um die Synchronizität der Daten kümmern zu müssen.
</p>

<p>
Fast-forward ein Jahr, tausche Linux gegen Apple und finde es jetzt doch sehr anstrengend, immer eine externe Festplatte mit mir herumzuschleppen &#x2013; Apple-Snob, der ich bin. Sieht auch unelegant aus, dieses schwarze Kästchen an den hübschen Laptop zu klemmen. Es muss also eine andere Lösung her, um immer auf beiden Rechnern mit aktuellen Dateien arbeiten zu können. Es bietet sich an: MobileMe (damals noch .Mac), genauer, die iDisk, also ein Stück online-Speicher bei Apple, auf dem man von mehreren (Apple-) Rechnern aus arbeiten kann. Das Angebot ist verlockend, aber leider erfüllt MobileMe meine Erwartungen nicht, es gehen Daten verloren und ich ärgere mich, jemals Geld für diesen Dreck ausgegeben zu haben.
</p>

<p>
Eine Alternative finde ich in Dropbox, welches die Vision des immer synchronen Datenspeichers "in the cloud" endlich erfüllt, wenn auch als Ordner und nicht als Laufwerk. Inzwischen erbringt auch Syncplicity diese Leistung, wenn auch mit einem eigenen Set an Einschränkungen (Es ist aber noch Beta, also kein Grund zur Sorge).
</p>

<p>
Dennoch: ganz zufrieden bin ich nicht, einfach, weil zwei Rechner immer eine gewisse Menge "mental overhead" bedeuten. Allein, nicht immer am selben Gerät zu sitzen stellt einfach eine Irritation dar, die im Grunde nicht nötig ist. Na gut, und dieses neue "Unibody"-MacBook Pro ist einfach sexy. Also, tausche iMac + MacBook gegen MacBook Pro. Das löst -logisch- auch alle Synchronizitätsprobleme.
</p>

<p>
Aber ich wäre nicht der Sohn meines Vaters, wenn ich nicht immer noch mehr technischen Schnickschnack haben müsste, enter: the iPhone. Dank Apple und iTunes ist es natürlich kein Problem, Kalender, Email, Kontakte und Musik immer synchronisiert zu halten; Kabel reinstecken, iTunes machen lassen und fertig.
Perfektioniert wird das alles aber erst durch Beihilfe von Google, welches durch ActiveSync (sprich: Exchange) nun auch alle meine Kontakte, Kalendereinträge, Emails und Dokumente auf allen Geräten zur Verfügung stellt. Dieses Setup ist nun endlich wirklich extrem zufriedenstellend. Es ist zwar ein Haufen Kleinkram, den man durcharbeiten muss, bis man das alles richtig konfiguriert hat, aber hat man das einmal getan funktioniert es wirklich tadellos! Und Syncplicity und Dropbox laufen auf dem Rechner einfach nur noch als Backup weiter.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-computers.html">computers</a> ]]></description>
  <category><![CDATA[computers]]></category>
  <link>https://bastibe.de/2009-03-28-synchronisieren-von-google.html</link>
  <guid>https://bastibe.de/2009-03-28-synchronisieren-von-google.html</guid>
  <pubDate>Sat, 28 Mar 2009 17:18:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[E Text Editor goes Open Source]]></title>
  <description><![CDATA[

<figure id="org1fbfb0d">
<img src="http://bastibe.de/static/2009-03/e_text_editor.png" alt="e_text_editor.png">

</figure>

<p>
Als ich heute von der FH nach Hause kam, lag <a href="http://e-texteditor.com/blog/2009/opencompany">das hier</a> in meinem Newsreader und ich war, in Ermangelung eines besseren Wortes, geschockt.
</p>

<p>
Nur, um es noch einmal zu wiederholen: E, der meiner Meinung nach beste Texteditor der Welt wird Open Source. Das kann man nicht oft genug sagen.
</p>

<p>
Warum ist E so fantastisch?
<a href="http://www.e-texteditor.com/">E</a> ist ein recht neuer, kleiner <a href="http://de.wikipedia.org/wiki/Texteditor">Texteditor</a> für Windows. Nein, um ihm Genüge zu tun, muss man E in einem Satz mit <a href="http://de.wikipedia.org/wiki/Emacs">Emacs</a>, <a href="http://de.wikipedia.org/wiki/Vim">Vim</a> und <a href="http://macromates.com/">Textmate</a> nennen, denn wie diese Drei Großen Texteditoren sind auch E keine Grenzen gesetzt, da all seine Funktionalität durch kleine, einfache Skripte entsteht, die von jedem Nutzer beliebig verbessert werden können. Genauer gesagt: E tritt in die direkten Fußstapfen von Textmate, einem Editor für den Mac und ist vollkommen kompatibel mit dessen Erweiterungen, so dass E schon bei seiner Markteinführung auf eine riesige Masse von <a href="http://svn.textmate.org/trunk/Bundles/">Sprachen, Snippets und Programmen</a> zurückgreifen konnte, mit der sich jede noch so obskure Textmanipulation bewältigen lässt. Anders als Emacs oder Vim folgt E dabei aber modernen Bedienungs- und Designrichtlinien und fühlt sich genauso flüssig und heimisch an, wie das für eine Windows-Anwendung nur möglich ist.
Seine zweite große, und kaum weniger berauschende Stärke ist sein <a href="http://e-texteditor.com/blog/2006/making-undo-usable">History-System</a>. Jeder Benutzer eines Texteditors kennt die Undo-Taste (<a href="http://stackoverflow.com/questions/247568/how-can-i-undo-more-than-a-single-character-in-textmate/248255">mit Ausnahme von Textmate</a>. <a href="http://nslog.com/2006/11/08/textmates_undo">What a shame</a>.). Undo macht die zuletzt gemachte Änderung rückgängig und ist damit der beste Freund von notirisch fehleranfälligen Menschen. E bringt Undo auf das nächste Level: Denn neben dem normalen Undo-Befehl gibt es noch eine komplette Übersicht aller jemals an einem Dokument gemachten Änderungen, komplett mit verschiedenen Pfaden, die zu verschiedenen Zeiten genommen wurden kompakt und übersichtlich verpackt in einem fantastischen Baumdiagramm.
Dazu kommen ein riesiger Haufen Features, die eigentlich jedes Programm haben sollte, welche man aber nur viel zu selten findet:
</p>

<ul class="org-ul">
<li>Inkrementielle Suche mit sofortiger Ergebnisvorschau und Unterstützung von Regulären Ausdrücken!</li>
<li>Direkte Unterstützung von Cygwin für alle möglichen Skriptsprachen!</li>
<li>Syntax-Highlighting für so ziemlich jede denkbare Sprache!</li>
<li>Unterstützung für Snippets!</li>
<li>Multiline-Editing!</li>
<li>Kontinuierliche Weiterentwicklung des Editors!</li>
<li>&#x2026;</li>
</ul>

<p>
Wer mehr wissen will, der surfe nach <a href="http://e-texteditor.com/index.html">e-texteditor.com</a> und schaue sich dort den Screencast und den Blog an, lade sich die Demo herunter oder suche im Internet nach Reviews zu E.
</p>

<p>
Selbst ich, als eingefleischter Textmate-Benutzer halte E als meinen heimlichen Lieblingseditor, denn schließlich kann er alles, was Textmate kann (und das ist schon enorm gut) und dazu noch eine gute Latte mehr. Wer, wie ich, eigentlich seinen Tag nur mit (a) surfen und (b) tippen verbringt, sollte wirklich darüber nachdenken, ein wenig Geld für einen guten Texteditor auszugeben. Es lohnt sich, und E ist ohne Frage einer der Besten. Und jetzt wird er Open Source. Ich bin begeistert!
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-text-editor.html">text-editor</a> ]]></description>
  <category><![CDATA[text-editor]]></category>
  <link>https://bastibe.de/2009-03-24-e-text-editor-goes-open-source.html</link>
  <guid>https://bastibe.de/2009-03-24-e-text-editor-goes-open-source.html</guid>
  <pubDate>Tue, 24 Mar 2009 15:16:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Western Digital Festplatten-Umtausch mit Überraschungen]]></title>
  <description><![CDATA[

<figure id="org28977f8">
<img src="http://bastibe.de/static/2009-03/festplatte.jpg" alt="festplatte.jpg">

</figure>

<p>
Ich hatte mir vor einer Weile eine externe Festplatte nur für TimeMachine gekauft. Denn TimeMachine ist super, die einzige Backup-Lösung die ganz bewusst nie in Erscheinung tritt es sei denn man braucht sie. TimeMachine läuft leise und unbeachtet im Hintergrund, und gibt mir dieses flauschige Gefühl von Sicherheit, quasi das unsicht- und spürbare Kondom der Computerwelt (bzw. Apple-Welt).
</p>

<p>
&#x2026;Bis ich einmal den fatalen Fehler beging, meine externe Festplatte HOCHZUHEBEN. Nicht ruckartig, nicht gewaltsam, sondern tatsächlich sehr sanft, aber wohl gerade zu einem ungünstigen Zeitpunkt, denn die Festplatte gab ein leises Klick von sich und hörte auf zu funktionieren.
</p>

<p>
Es handelt sich hierbei um eine externe Festplatte der Marke Western Digital MyBook mit 500 Gigabytes, gekauft bei Norskit. Ein Anruf beim Verkäufer ergab, dass dies eine alte Bestellung (weltbewegende 9 Monate) sei und ich daher bei einer anderen Nummer anrufen sollte. Eine sehr freundliche Mitarbeiterin teilte mir dort mit, dass die Firma leider Insolvent sei und ich meine Supportanfrage daher an den Hersteller richten sollte. Und was soll ich sagen? EIN GLÜCK, dass sie das sagte!
</p>

<p>
Denn auf der Webseite von Western Digital gibt es nicht nur eine Support-Telefonnummer, sondern gleich ein komplettes austausch-Programm für Festplatten, welches vollkommen automatisiert abläuft: Man gibt die Modellnummer seiner Festplatte und -für Notfälle- seine Email-Adresse an und bekommt sofort eine neue Festplatte zugeschickt, mit der einzigen Auflage, die alte, defekte Platte innerhalb von 30 Tagen einzuschicken. Und tatsächlich wurde die neue Platte prompt am nächsten Tag verschickt und kam heute pünktlich per UPS bei mir an.
</p>

<p>
Faszinierend, so wünsche ich mir Kundenservice. Der einzige Wermutstropfen ist, dass Western Digital offenbar nicht sehr überzeugt von der Ausfallsicherheit seiner Festplatten ist, wenn sie so viel Infrastruktur für den einfachen Austausch bereitstellen&#x2026; Na egal, ich will mal nicht meckern ;-)
</p>

<p>
<b>Nachschlag:</b> Es stellt sich heraus, die neue Festplatte unterscheidet sich ein wenig von der alten: Sie ist silber statt schwarz und hat zwei Firewire 800 Anschlüsse anstatt Firewire 400 &#x2013; ein Glück, dass auch Kabel mitgeliefert wurden, sonst könnte ich sie jetzt nicht anschließen!
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-computers.html">computers</a> ]]></description>
  <category><![CDATA[computers]]></category>
  <link>https://bastibe.de/2009-03-19-western-digital-festplatten-umtausch-mit-uberraschungen.html</link>
  <guid>https://bastibe.de/2009-03-19-western-digital-festplatten-umtausch-mit-uberraschungen.html</guid>
  <pubDate>Thu, 19 Mar 2009 21:17:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Debugging und GCC auf Windows]]></title>
  <description><![CDATA[

<figure id="org851f261">
<img src="http://bastibe.de/static/2009-03/code.png" alt="code.png">

</figure>

<p>
So, jetzt habe ich mein Mex-File zum Einlesen beliebiger Audiodateien endlich lauffähig auf Windows und Mac. Leider werde ich nicht dafür bezahlt, auch noch eine Linux-Version zu bauen, aber falls Interesse besteht, versuche ich mich vielleicht einmal daran.
</p>

<p>
<a href="http://en.wikipedia.org/wiki/State_of_the_Union">The State of The Union</a>: Kleine Dateien einlesen, kein Problem. Exotische Formate einlesen, kein Problem. Metadaten auslesen, kein Problem. Dateigröße, Bitrate und Samplerate auslesen, ein kleines Problem, da diese Parameter bei komprimierten Formaten nicht unbedingt fest stehen. Große Dateien einlösen, auf dem Mac kein Problem, auf Windows… nun ja, es dauert. Eine WAV-Datei von 5:30 min einzulesen, dauert mit Windows momentan ca. eine Stunde. Das kann nicht sein, in der Zeit habe ich die Datei dem Programm vorgelesen, wenn es sein muss.
</p>

<p>
Also, was ist da faul? Jetzt heißt es debuggen: <a href="http://de.wikipedia.org/wiki/GNU_Debugger">GDB</a> ist mein Freund, aber leider spreche ich seine Sprache nicht, also Oldschool-Debugging mit <a href="http://www.cplusplus.com/reference/clibrary/cstdio/printf.html">printf()</a> (bzw. <a href="http://www.mathworks.com/access/helpdesk/help/techdoc/index.html?/access/helpdesk/help/techdoc/apiref/mexprintf.html">mexPrintf()</a>; Aber da `#define printf mexPrintf` ist das das selbe). Blöd nur, dass Matlab selbst entscheidet, wann es meine Printfs auf den Bildschirm schreibt und es sich dazu entschlossen hat, dies immer erst nach dem Ausführen der Datei, also erst nachdem es bereits eine Stunde gearbeitet hat, zu tun. Einiges Hirnen später konnte ich Matlab endlich über eine Kombination aus <a href="http://de.wikipedia.org/wiki/Typumwandlung">Typecasts</a>, <a href="http://www.cplusplus.com/reference/clibrary/cstdio/sprintf.html">sprintf</a> und <a href="http://www.mathworks.com/access/helpdesk/help/techdoc/index.html?/access/helpdesk/help/techdoc/apiref/mexwarnmsgtxt.html">mexWarnMsgTxt</a> dazu überreden, wenigstens sporadisch ein paar Informationen herauszugeben.
</p>

<p>
Das Ergebnis:
</p>

<ol class="org-ol">
<li>Die Datei funktioniert tadellos, ist nur ein wenig langsam (s.o.)</li>
<li>Wer ist schuld? <a href="http://www.cplusplus.com/reference/clibrary/cstdlib/realloc.html">Realloc</a> ist schuld!</li>
</ol>

<p>
Das kam überraschend! Offenbar ist realloc auf dem Mac um mehrere Größenordnungen performanter als auf <a href="http://www.mingw.org/">MinGW</a>/Windows, denn die selbe Anwendung, die auf dem Mac ca. eine Sekunde braucht, braucht auf Windows eine Stunde! Und das allein wegen realloc! (Eigentlich: eine halbe Stunde wegen realloc, der Rest ist der Tatsache geschuldet, dass Windows in einer <a href="http://www.vmware.com/de/products/fusion/">VM</a> läuft)
</p>

<p>
Bei WAV-Dateien werden immer 2048 Samples an einem Stück ausgelesen. Danach verwende ich ein realloc, um meinen haupt-Speicherpuffer um diese Größe zu vergrößern und kopiere die neuen Daten dort hinein. Bei meinen 5:30 min macht das bei einer Samplerate von 44100 kHz und zwei Kanälen ca. 15000 Aufrufe von realloc. Komprimierte Datenformate haben üblicherweise kleinere Frames und damit noch einmal wesentlich mehr realloc-Aufrufe.
Der Plan ist also, jetzt statt häufiger, kleiner realloc-Aufrufe, seltenere, größere Aufrufe zu machen. Zeit für ein paar Experimente:
</p>


<table>


<colgroup>
<col  class="org-left">

<col  class="org-right">

<col  class="org-left">
</colgroup>
<tbody>
<tr>
<td class="org-left">realloc()-Größe</td>
<td class="org-right">realloc()-Aufrufe</td>
<td class="org-left">benötigte   Zeit</td>
</tr>

<tr>
<td class="org-left">2<sup>11</sup> =    2048</td>
<td class="org-right">15000</td>
<td class="org-left">~1 h</td>
</tr>

<tr>
<td class="org-left">2<sup>16</sup> =   65536</td>
<td class="org-right">470</td>
<td class="org-left">~2 min</td>
</tr>

<tr>
<td class="org-left">2<sup>17</sup> =  131072</td>
<td class="org-right">240</td>
<td class="org-left">~1 min</td>
</tr>

<tr>
<td class="org-left">2<sup>18</sup> =  262144</td>
<td class="org-right">120</td>
<td class="org-left">30 s</td>
</tr>

<tr>
<td class="org-left">2<sup>19</sup> =  524288</td>
<td class="org-right">60</td>
<td class="org-left">18 s</td>
</tr>

<tr>
<td class="org-left">2<sup>20</sup> = 1048576</td>
<td class="org-right">30</td>
<td class="org-left">10.5 s</td>
</tr>

<tr>
<td class="org-left">2<sup>21</sup> = 2097152</td>
<td class="org-right">15</td>
<td class="org-left">7.3 s</td>
</tr>

<tr>
<td class="org-left">2<sup>22</sup> = 4194304</td>
<td class="org-right">7</td>
<td class="org-left">5.1 s</td>
</tr>

<tr>
<td class="org-left">2<sup>23</sup> = 8388608</td>
<td class="org-right">3</td>
<td class="org-left">4.2 s</td>
</tr>
</tbody>
</table>

<p>
Das Spannende ist: Ich ändere durch meine Methodik praktisch nichts außer der Anzahl und Größe der realloc-Aufrufe, aber man erkennt einen eindeutigen Zusammenhang zwischen Performance und Anzahl der Aufrufe, ergo ist realloc der alleinige Schuldige für mein Performanceproblem auf Windows.
</p>

<p>
An dieser Stelle fiel mir ein, dass ich bereits an früherer Stelle einmal die gesamte Länge des Audio-Streams anhand der Metadaten geschätzt hatte. Durch eine somit vorgenommene Prä-Allokation des gesamten Speichers lässt sie die Laufzeit weiter auf 2.2 s drücken. Das ist immernoch nicht einmal halb so schnell wie auf OSX (0.9 s), aber das mag auch an der virtuellen Maschine liegen.
</p>

<p>
Mehr als diesen anecdotal Evidence kann ich nicht anbieten, aber ich bin mir sicher, dass ich ab jetzt die Finger von inkrementiellen Speichervergrößerungen auf MinGW/Windows lassen werde. Ist das in MSVC ähnlich schlimm, oder habe ich da etwa einen Bug entdeckt?
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-compiling.html">compiling</a> <a href="https://bastibe.de/tag-windows.html">windows</a> ]]></description>
  <category><![CDATA[compiling]]></category>
  <category><![CDATA[windows]]></category>
  <link>https://bastibe.de/2009-03-15-debugging-und-gcc-auf-windows.html</link>
  <guid>https://bastibe.de/2009-03-15-debugging-und-gcc-auf-windows.html</guid>
  <pubDate>Sun, 15 Mar 2009 15:10:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Get a Mac]]></title>
  <description><![CDATA[

<figure id="org4ca4d82">
<img src="http://bastibe.de/static/2009-03/osx.png" alt="osx.png">

</figure>

<p>
Bei meinem üblichen, Samstagmorgendlichen, bettlägrigen Web-Rundgang habe ich heute drei sehr nette Artikel von David Alison gefunden, einem Windows-Programmierer und selbsternanntem Microsoft-Fanboy, der sich einen Mac zulegt und unverhofft glücklich damit wird. So glücklich sogar, dass er inzwischen mehr oder weniger ein Mac-only-User geworden ist.
</p>

<p>
Ziemlich genau wie ihm ging es mir auch.
</p>

<ul class="org-ul">
<li>Teil 1: <a href="http://www.davidalison.com/2008/02/hardcore-windows-guy-switches-to-mac.html">A hardcore Windows guy gets a Mac</a></li>
<li>Teil 2: <a href="http://www.davidalison.com/2008/04/mac-after-two-months-of-mac-heres-why-i.html">After two months of Mac, here's why I switched</a></li>
<li>Teil 3: <a href="http://www.davidalison.com/2009/03/switching-from-windows-to-mac-one-year.html">Switching from Windows to Mac - One Year Later</a></li>
</ul>

<p>
Wens interessiert: Das ist eine sehr hübsche Einführung darin, warum Macs toll sind. Viel besser als alles, was ich dazu schreiben würde oder <a href="http://www.meinstudi.de/basti/?p=49">bereits</a> <a href="http://www.meinstudi.de/basti/?p=4">getan</a> <a href="http://www.meinstudi.de/basti/?p=24">habe</a>.
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-macos.html">macos</a> ]]></description>
  <category><![CDATA[macos]]></category>
  <link>https://bastibe.de/2009-03-14-get-a-mac.html</link>
  <guid>https://bastibe.de/2009-03-14-get-a-mac.html</guid>
  <pubDate>Sat, 14 Mar 2009 10:24:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Kompilieren auf Windows]]></title>
  <description><![CDATA[

<figure id="org2d5fa12">
<img src="http://bastibe.de/static/2009-03/open_source_rules.png" alt="open_source_rules.png">

</figure>

<p>
Seit einigen Wochen arbeite ich an einem kleinen Projekt: Eine Matlab-Funktion, die, ähnlich wie die standard-Funktion <a href="http://www.mathworks.com/access/helpdesk_r13/help/techdoc/ref/wavread.html">wavread()</a>, Audiodateien einlesen kann. Aber nicht irgendwelche Audiofiles, sondern ALLE MÖGLICHEN Audiofiles. Wie geht das? Jeder kennt <a href="http://www.videolan.org/vlc/">VLC</a>, den Video-Player, der so ziemlich jedes Video öffnen kann, das man ihm vorsetzt, selbst wenn man überhaupt keine Codecs installiert hat. VLC basiert auf <a href="http://de.wikipedia.org/wiki/FFmpeg">FFmpeg</a>, einem Open-Source Programm, welches Funktionen bereit stellt, um eben alle möglichen Mediendaten zu öffnen.
</p>

<p>
Und da FFmpeg freie Software ist, kann man sie auch für andere Dinge verwenden, etwa, um mit Matlab Audiodateien zu öffnen. Fehlt noch eine Verbindung zwischen Matlab und den FFmpeg-C-Bibliotheken, und die gibt es in Form von <a href="http://www.mathworks.com/support/tech-notes/1600/1605.html#intro">Mex</a>, der C-Schnittstelle von Matlab. Feine Sache, zwar hat es eine Weile gedauert, bis ich mich in libavformat und libavcodec eingearbeitet hatte (die beiden wichtigsten FFmpeg-Bibliotheken), aber im Endeffekt lief das alles sehr schmerzfrei &#x2013; und das, obwohl ich bisher Mex-Kompilieren mit Matlab immer als eine grausige Beschäftigung in Erinnerung hatte, gespickt von kryptischen Kompiler-Fehlern und hässlichen Notlösungen.
</p>

<p>
Bumms, Zack, kaum hatte ich mich versehen, hatte ich ein lauffähiges, tadellos funktionierendes <a href="http://en.wikipedia.org/wiki/MATLAB#Calling_C_and_Fortran_functions">Mex-File</a> auf meinem Mac liegen. Damit hatte ich nicht gerechnet. Also sofort die momentane Euphorie ausnutzen und weiter zu Schritt 2, das Ganze nochmal auf Windows. Meine Probleme, Windows so einzurichten, dass ich endlich Kompilieren kann, <a href="http://www.daskrachen.com/2009/03/great-scott.html">hatte ich ja schon berichtet</a>. Ich hatte also Visual Studio 2005 installiert, um Matlab zufrieden zu stellen und einen anständigen Kompiler auf dem System zu haben. Aber war ja klar, MSVC macht wieder sein eigenes Ding und nichts ist mit Standardkonformität und Trallalla: Keine <a href="http://de.wikipedia.org/wiki/C99#C99">C99</a>-Unterstützung, also keine Variablendeklarationen mitten im Code und keine stdint.h oder inttype.h. Ein Glück, es gibt wieder ein wenig mehr Free Software, die wenigstens <a href="http://code.google.com/p/msinttypes/">letztere Lücke schließt</a>. Dennoch; Ich bekomme mein mex-File nicht zum Laufen. Es ist wie verflucht, kaum setze ich mich an eine Windows-Maschine zum Programmieren, fällt meine Produktivität auf das Niveau eines Backsteins.
</p>

<p>
Enter <a href="http://sourceforge.net/projects/gnumex">gnumex</a>, noch ein weiteres Stück FOSS, das es ermöglicht, GCC als Mex-Kompiler zu verwenden, AUF WINDOWS. Um die Dinge zu vereinfachen, verwendete ich die <a href="http://www.mingw.org/">MinGW</a>-Variante und kaum war diese Hürde genommen&#x2026; lief alles. Einfach so. Wahrscheinlich bin ich ein Dickschädel und habe einfach nicht die Geistesschärfe, mit Windows-Kompilern zu arbeiten, aber mir scheint, alles was ich diesbezüglich anfasse und das nicht GCC heißt ist zum Scheitern verurteilt. Ein Glück, dass es die vielen klugen Jungen und Mädchen gibt, die so wunderbare freie Software schreiben, die mir das Leben so viel einfacher macht!
</p>

<p>
Eine Fortsetzung kommt noch&#x2026;
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-compiling.html">compiling</a> <a href="https://bastibe.de/tag-matlab.html">matlab</a> <a href="https://bastibe.de/tag-windows.html">windows</a> ]]></description>
  <category><![CDATA[compiling]]></category>
  <category><![CDATA[matlab]]></category>
  <category><![CDATA[windows]]></category>
  <link>https://bastibe.de/2009-03-12-kompilieren-auf-windows.html</link>
  <guid>https://bastibe.de/2009-03-12-kompilieren-auf-windows.html</guid>
  <pubDate>Thu, 12 Mar 2009 17:14:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Vom Sinn und Unsinn, ein Cross-Platform-Compiling-Matlab-System aufzubauen]]></title>
  <description><![CDATA[

<figure id="orge55b77e">
<img src="http://bastibe.de/static/2009-03/bitte_warten.png" alt="bitte_warten.png">

</figure>

<p>
Mal wieder: Ich schreibe ein Stück Software für meinen Nebenjob bei meinem Signalverarbeitung-Prof. Diesmal geht es darum, beliebige Audio-Files in Matlab einlesen zu können. Perfekt geeignet ist dafür die selbe Bibliothek, die auch von VLC verwendet wird, libavcodec/libavformat. Das ist eine normale C-Bibliothek, es braucht also nur noch ein kleines mex-File, um ihre Funktionalität für Matlab zur Verfügung zu stellen. Klappt auch wunderbar. Auf dem Mac.
</p>

<p>
Schritt zwei ist dann, das Ganze auf Windows und Linux zum Laufen zu bringen. Eigentlich kein Problem, denn ich habe keine wilden Dinge getan und die Libraries selbst sind wunderbar Cross-Platform, es gibt sie sogar schon vorkompiliert für praktisch jedes denkbare Betriebssystem.
</p>

<p>
Also, was brauche ich? Zwei Dinge: Matlab und einen C-Compiler (der mitgelieferte LLC-Compiler macht mein Hirn bluten). Matlab zu installieren ist meiner Erfahrung nach schmerzhaft. Bigtime. Nicht, weil Matlab schwer zu installieren wäre, sondern, weil Mathworks nur zwei Installationen pro Schachtel erlaubt, was für meine drei Betriebssysteme zu gewissen Problemen führt. Außerdem müsste ich meine eine Lizenz erst für die Windows-installation umschreiben lassen, und&#x2026; ach, Schmerzen. Offenbar habe ich die Jungs dort aber schon derart häufig mit Lizenzanfragen genervt, dass sie mich einfach als hoffnungslos aufgegeben haben, denn dieses Mal musste ich keine neue Lizenz erstellen lassen, sondern einfach installieren, Passwort eingeben, und los. Mein Account meldet jetzt, dass ich fünf gleichzeitige Installationen hätte (von zwei erlaubten). Mir solls Recht sein.
</p>

<p>
Außerdem: ein aktuelles Linux muss her. VMWare sei Dank, lauert im Linux-Installieren nicht mehr der Schrecken, im Zweifelsfall den kompletten Festplatteninhalt zu verlieren, sondern nur noch, an akuter Progressbar-itis zu ersticken. War ja klar, dass Autoupdate sich diesen Nachmittag aussucht, um meine Ubuntu-VM hoffnungslos zu zerstören. Also, neues Ubuntu heruntergeladen, neu installiert, neu Updates aufgespielt, zwei Stunden Lifetime verloren. Immerhin: es hat fehlerfrei funktioniert, das ist was Neues. Matlab hinterher, VMWare Tools dazu, fertig ist die Development-Kiste. Jetzt fehlt nur noch eine Verbindung zu meinem Development-Verzeichnis, damit ich auf meine Dateien zugreifen kann. Fehlanzeige. Dukommsthiernichrein. Na Toll.
</p>


<figure id="orgf252a47">
<img src="http://bastibe.de/static/2009-03/upgradepatch.png" alt="upgradepatch.png">

</figure>

<p>
Also weiter zu Windows. Frühere Versuche ergaben bereits, dass ich Matlab nicht dazu bewegen kann, (a) GCC als Compiler zu nehmen oder (b) das bereits installierte Microsoft Visual Studio C++ .Net Professional Directors Cut Special Edition 2008 Ultimate zu verwenden. Nähere Nachforschungen zeigen: Zu neu, Kennternich. Geht nur bis MSVC Jahrgang 2005. Also: Neues MSVC deinstallieren, Altes installieren. ich freue mich immer darauf, MSVC zu deinstallieren, denn es besteht lediglich aus kompakten 12 Programmen, die sich zwar alle auf einem Haufen Installieren- jedoch nicht De-Installieren lassen. Immerhin ist es dank MSDNAA-Membership nicht schwer, an die alten Versionen heranzukommen. Und klar, die Systemsteuerung lässt einen auch immer nur ein Programm auf einmal deinstallieren. Multitasking ist nicht. Dank Syncplicity kann Windows die Zwischenzeit immerhin dazu verwenden, all meine Development-Files auf den Rechner zu laden. Yay!
Das Schöne an Fortschrittsbalken ist ja, sie zeigen Fortschritt. Damit haben sie einen klaren Vorteil gegenüber etwa Dachbalken oder den Bittewartenpunktpunktpunkt-Balken, die die Microsoft SQL Server 2008-Deinstallation stolz herumzeigt. Die fühlt sich wohl sehr wichtig, denn sie rödelt eine starke halbe Stunde im Bitte-Warten-Modus herum. So mag ich Deinstallationen.
</p>

<p>
To be continued&#x2026;
</p>
<div class="taglist"><a href="https://bastibe.de/tags.html">Tags</a>: <a href="https://bastibe.de/tag-matlab.html">matlab</a> <a href="https://bastibe.de/tag-compiling.html">compiling</a> ]]></description>
  <category><![CDATA[matlab]]></category>
  <category><![CDATA[compiling]]></category>
  <link>https://bastibe.de/2009-03-05-great-scott.html</link>
  <guid>https://bastibe.de/2009-03-05-great-scott.html</guid>
  <pubDate>Thu, 05 Mar 2009 13:55:00 +0100</pubDate>
</item>
</channel>
</rss>
