# December Adventure 2025
Low-key code-based fun in December 2025.
The Advent of Code is cool, but a lot, and not everyone’s jam. The December Adventure is low key. The goal is to write a little bit of code every day in December. – eli.li/december-adventure
Microblog thread at post.lurk.org.
See also: December Adventure 2024.
# 1 One
# 1.1 AM
Before December started I was working on some node-edge graph layouts, and failed at “nesting” (irregular shape packing) so switched to a simple grid layout.
On December 1st, I added rotation optimisation to my grid layout to avoid clashes.
Filling items left to right top to bottom: pick the rotation (by trying many rotations and picking the best) of each next item that maximizes the minimum (squared) distance between the item and the items immediately left and above.
# 1.2 PM
In the afternoon I finished adding separate in/out audio channel counts to clive, work that had been partly completed earlier. Clive is my thing for live-coding audio DSP in the C programming language.
The channel counts are still hardcoded at engine build time:
- JACK: 2 in / 18 out (2 stereo + 16 to exwhyscope for debugging)
- everything else: 0 in / 2 out.
I put a prototype in the dsp.h header so that these
changes will fail at build time instead of crashing.
This also means client user code needs to change from
typedef struct { ... } S;
int go(S *s, int channels, const float *in, float *out, event
s_t *events) { ... }
to
struct S { ... };
int go(S *s, int inchannels, const float *in, int outchannels, float *out, event
s_t *events) { ... }
All branches in the clive-core repository are now up to date.
git clone https://code.mathr.co.uk/clive-core.git
(No web access any more due to bad robots, but the git tool should still work.)
# 2 Two
# 2.1 AM
I did a fair amount of work on clive, combining the separate client (compiler) and server (audio + osc) into one program, renaming lots of things to be more consistent.
The main advantage of this change is that the audio part
can tell the compiler what the audio engine’s sample rate is,
so no need to define it by hand in the live/clive.c file (previously client/go.c).
I tagged as v1 the version before all these disruptive changes.
Summary of user-facing changes in the last couple of days:
diff --git a/client/go.c b/live/clive.c
index 84f7163..0b65cae 100644
--- a/client/go.c
+++ b/live/clive.c
@@ -1,13 +1,12 @@
typedef float sample;
-#define SR 48000
-#include "dsp.h"
+#include <clive.h>
-typedef struct
+struct clive_state_t
{
int reloaded;
// state
-} S;
+};
-int go(S *s, int channels, const float *in, float *out, events_t *events)
+int clive_audio(clive_state_t *s, int inchannels, const float *in, int outchannels, float *out, events_t *events)
{
if (s->reloaded)
@@ -25,5 +24,5 @@
// output
- for (int c = 0; c < channels; ++c)
+ for (int c = 0; c < outchannels; ++c)
and run ./bin/clive.sh instead of ./launch/local-native-sse.sh.
# 2.2 PM
tl:dr clive for windows wip
I factored out the platform-specific code in clive:
- inotify used for file watching (linux, also available on freebsd15 apparently)
- dl used for loading compiled code (posix)
- sockets used for osc server (posix)
I will probably switch from C11 threads.h (not supported by llvm-mingw or old systems)
to pthreads for better portability.
Audio backends still need to be checked, possibly some non-portable bits lurking.
I started a Windows version of the file watcher but it didnt’t work when built with mingw64 and run with hangover-wine in termux on android. Later I tried on Debian desktop Wine and it worked fine.
The strategy I have for platform specific code is a layout like:
watch.h
linux/watch.c
windows/watch.c
and the build system picks the correct implementation.
Better than a confusing mess of #ifdefs imo.
# 3 Three
# 3.1 AM
Got clive working on Windows (at least, it works in Wine), Custom file watcher code using Windows APIs, also dlopen replacement (which was mostly similar to Linux). OSC server is still missing.
The build system is set up to cross-compile clive.exe from Debian,
but clive.exe invokes onchange.bat which compiles clive.c to clive.dll
using Windows llvm-mingw EXEs. Also Windows PortableGit git.exe is used.
# 3.2 PM
Found my Bela, and got networking over USB working with my Debian Trixie desktop.
Tried cross-compiling for clive, but
ERROR: version `GLIBC_2.29' not found
which means Debian Trixie compiler is too new for Debian Stretch Bela.
# 4 Four
# 4.1 AM
Documented how to get clive working on Bela, using a Debian Stretch chroot on Debian Trixie host.
Full details in the README.md in the clive-core repository.
# 4.2 PM
Documented recent work on the 4D Hopfbrot fractal.
Updated my cross-compilation build scripts.