2023 12
A December Adventure Posts are in reverse order, latest first.
23
Meeting some old school friends today for drinks. Wish me luck. For the December Adventure I’ve started a CLI (in Kotlin script) for controlling my Cambridge Audio streamer (scroll to bottom): AXN10
22
I’ve started using the Obsidian daily log, which should be over there in the sidebar. Tech-wise my domain now points at this vault: orllewin.ukand I’ve added lots more entries. I also decompiled the Cambridge Audio StreamMagic app so I could look at how my AX10 streamer works. I’ve started documenting the API here: AXN10, it should be pretty trivial to create an alternative app for it. ## 21
Travelling home today, so no time for coding, I’m on the train wrapping up some dayjob work before the Xmas break. I did spend last night in the hotel moving my old software projects from Codeberg to Github, and referencing them here in this Obsidian vault (all available to browse in the sidebar to the left).
20
On-site day with the day job, so no project work. On the train down
yesterday though I rewrote my net-radio project. Previously I’d
implemented it with KotlinJS and
it was having some new issues with CORs, possibly due to me stopping
paying for Neocities. Fixing it
would have meant finding the original project and probably ignoring
Jetbrains IDEA prompts to update all the build dependencies. Instead I
rewrote the project from scratch in three files:
index.html
, style.css
, and
script.js
and removed the external JSON file dependency
entirely, instead encoding the various parameters as a Base64 query
string. It’s installable as PWA, and sets the audio metadata so works
really well on mobile (or at least Android): https://orllewin.github.io/radio/
## 19
A travel day, heading down to Salisbury for an on-site work visit.
As usual I’m the only person wearing a mask on the train. Even without
COVID it’s a good habit, why risk getting a cold just before
Christmas. Tech-wise I’ve switched to a sampleplayer
for
the Granular module as mentioned yesterday, it has fixed the
ui-locking problems so the input automation sockets can stay - which
is a relief because it sounds fantastic. I’ve also done some
lower-tech work, pulling together various projects and crafts into
this Obsidian vault, you should be able to browse in the side-bar to
the left.
18
I ran Granular on hardware and it works great except for the clock
sync, those subsamples really do hit the framerate too much, two
choices: remove the clock input sockets entirely or rewrite the
subsample logic. The subsamples currently involve file io, which is
slow of course, but in-memory subsamples was showing some weird
behaviour with the Playdate sound API, switching from
sampleplayer
to fileplayer
fixed everything.
The code has been much improved and simplified since then, maybe
reverting to sampleplayer
would be fine…
I’ve also ported the ModularPlay manual web page to here on Obsidian: ModularPlay. Doing this daily update for December Adventure has reminded me how much more convenient Obsidian is than manually writing web pages.
17

Little progress on anything today, other than parenting; we visited Samlesbury Hall. I’ve fixed the start and end constraints in the Granular module. Getting granular sounds back into Granular won’t be possible though I don’t think, at least not without significant effort - the pseudo oscillator module is based on a timer, and in order to not impact the ui performance too much it’s fairly slow. To slowly step through a sample at a granular scale the oscillator would need to perform at much smaller discreet increments, any other way of implementing it would still require high frequency updates, with the Playdate being single-threaded it’s just asking too much. The module sounds fantastic though, it’s just badly named. Even in ‘normal’ use as a random looper it still locks the ui occasionally when it’s generating a subsample. Monday tomorrow, so lots of day job work to do, but I’ll try and record a video with progress to far running on hardware.
## 16
The Granular module in ModularPlay on Playdate is now stable. Still some work to do with the start and end limit points, and it’d be useful to display which sample is loaded, but other than that it’s in, already more useful than the standalone Granular app; you have access to everything else already in ModularPlay. It’s the weekend, we have kids Christmas fairs and things to go to, I’m not sure if I’ll find time to do more coding.
15
Granular inside Modular Play! I’ve never seen the Playdate crash so much as while developing this. The sample player API doesn’t like what I’m trying to make it do here. It’s still extremely buggy and fragile, the start/end range bars don’t work correctly, it crashes if you change sample more than once, it crashes if you look at it wrong, it’s not hooked up to the patch cable system yet, you can’t change octave range, etc etc but… it already sounds great.
14
Lento 2 building, slowly bringing the dependencies up-to-date. Android is terrible, you have to juggle Gradle versions, Kotlin versions, multiple dependency versions, OS versions and their ever-changing breaking API policies, particularly around file io permissions - any of which can break and leave you hunting solutions on Stack Overflow with other unfortunate souls, and it all requires a huge amount of network bandwidth which we don’t have here up on the hill.
In happier news I’ve started bringing Granular functionality over to ModularPlay. Granular’s main screen was great but the effects section wasn’t as well designed. If I can get the same audio experience I think I’ll code-freeze Granular and add a note to use ModularPlay instead. This was spurred by Luca posting this lovely clip using Granular:
Because ModularPlay is … modular, all that needs writing to get all Granular features is the main sub-sample selection, the random moving logic, the nice track view, there’s already a Sample Playback module which handles loading samples which I’ve cloned to turn into ‘GranularMod’. Each Granular module will have a single track, to mirror the Granular app you just add five granular modules and whatever effects you like. I might also add some automation - so you could control movement via an oscillator or a new random position in time with some external clock event.
13
Having a day off projects, although I have started bringing back Lento from the dead. The page makes little sense currently as it’s just a copy-paste of the original page from when it was available on Google Play: orllewin.github.io/android/lento. I’ve pulled the Lento 2 repository to try and get that building again, some screens may need rewriting in Compose, the main Camera screen can stay using old-school XML though, I’m going to reduce the scope and just have a bare-bones functional LUT camera. I’ll rip out the support for anamorphic lenses too, Moment cases kept falling apart on me and the hard-sell marketing started to grate too much.
The old webpage also had a hacked together javascript gallery: orllewin.github.io/android/lento/gallery/001/. It’s nice seeing the example photos featuring my kids, and how much they’ve grown in the year or two since the Lento page was put together:

12
No work on ModularLöve today, instead I’m trying to set up Nova IDE for C development. Creating a
custom build and run task is simple enough, but the only way I can
find of getting syntax highlighting is by using the C-Dragon plugin.
That can’t see SDL which my build task is linking via clang:
clang main.c -I/Library/Frameworks/SDL2.framework/Headers -F/Library/Frameworks -framework SDL2 -o HelloSDL
.
I’m a beginner with C but C-Dragon setup seems a bit obtuse and I’d
prefer to use Nova than Xcode. I have just found the Icarus extension via the
web, will see if I can make better progress with that (Update: Icarus
did indeed work perfectly):
Yesterday I also managed to finish the Ever-Ready bike light project, short video here: youtube.com/shorts/s2od27oFNTo?si=hwue9HoYmk3jcEGj
## 11
A Monday, very busy, but I’ve added Flanger and Ring Modulator modules. I’ve also pushed a public repository and released the project under the Parity License.
github.com/orllewin/love2d_modular_love
10
Timed switches, so you can toggle different parts of a patch, not
very musically interesting this recording but it also serves as a
stress test with a large number of modules. Every module does have a
check in it’s draw method so that it can determine if it’s on-screen
or not before drawing but at the moment it’s unimplemented and just
returns true:
if self:visible(x, y) then --do drawing operations ... end
,
maybe that’ll be the next bit of work. I’m also trying to decide
whether I have the time and energy to develop this further and
eventually sell it on itch.io or to just find a suitable license and
put it in a public repo:
9
Posting this a little early as I’m unlikely to get much free time this weekend. I’ve added a couple of the smaller modules from the Playdate version to ModularLove: Bifurcate 2 which splits/duplicates an event, and the Blackhole module which swallows random events depending on the gravity level. This little patch has some moments that sounds a little like Bola.
Relaxen und watchen das blinkenlichten.
8
More effects: Chorus, Delay, Distortion, Reverb, and Compressor. The midi keyboard has been improved quite a bit, it now takes input from the computer keyboard, with a shift modifier to move up an octave. Plus and Minus also shift the octave range up and down.
7
Effects pedals. I’m not sure how LÖVE combines effects, I don’t think when you chain a reverb after a chorus the chorus is having reverb applied etc etc. The distortion is lacking low end too, I’ll have a look at filters next I think.
6
A lot of progress, but I might slow down and look for something a bit more off the beaten path to work on for a while. I’ve completed the clock modules by adding Clock Delay and Clock Divider - both simple because Delay was already implemented in the Generative module, and Divider just emits every other event. An on-screen midi keyboard is also largely done, the only thing it doesn’t have from the Playdate version is the ability to move up and down octaves. I’ve also added the logic to move cables when you move a module, it breaks visually in some circumstances but it’s largely finished.
5
- Bubble Chamber ‘clock’ added, when a molecule hits a module side a clock event is emitted.
- A copy of Generative Std. called Generative Small, has everything the original has apart from the clock delay and black hole.
- The sample synth now has two samples internally, so if two notes are played in quick succession the first can decay naturally. If both are playing when a third note comes in one is picked at random to stop and re-trigger with the new note.
- Ability to move a module by pressing ‘m’ while hovering (doesn’t move any attached cables yet).
4
We’re snowed-in, so this morning I have to walk the eldest to school before finding somewhere to work in the valley (Update: we did get out in the car without issue in the end). I have finished the ‘Generative’ module though, all the behaviour from the Playdate version is in place: when the module receives a clock event there’s a 1 in 4 chance of the note being delayed by the set interval, the gravity encoder sets the chance of the event being swallowed entirely by a blackhole, and the rest of the controls set the key and scale, and the pitch range.
I found some time throughout the day to start work on the front
light of the Ever-Ready Exide modernisation project:
3
Today’s adventure was adding a dropdown menu so modules can easily set different parameters. As only one dropdown can be shown at a time it’s actually a single view shared by all modules, they just set the items and coordinates and listen for the selected index. Adding this means the sample synth can now change samples, not what I planned to work on today but we’ve had snow and I need to take the kids out to play and fetch the Christmas tree from storage. Towards the end of the video you can see a new option to toggle the module type labels by pressing a key.
2
Today I added a rotary encoder to the clock and all the logic
required to add knobs and sliders to modules by capturing the mouse
down and mouse move combination correctly: when there’s a mouse down
event the framework looks for a collision with a module, then it asks
the module if it accepts scroll events, if it does a
controlLock
boolean is set, from that point all scroll
events are sent to that individual module until a mouse up event
resets controlLock
. At the moment there’s a basic
clock-event-to-midi-note Generative module which emits a random C
Pentatonic scale note - the next step is to port the rest of that
modules feature from Modular Play.
1
I’ve started porting Modular Play to LÖVE. It started a few days ago getting the basic framework in place for a ‘canvas’/patch which you can drop modules onto and connect with ‘catenary curve’ cables: YouTubeYou can click and drag with a mouse to pan around the canvas, or use a two-finger scroll on a trackpad to do the same. Dragging a cable from one module to another is done with the ‘c’ key and mouse - it all feels very intuitive. One last thing I added late at night was copy/paste - you can ‘command-c’ while hovering on a module to copy the module type, then ‘command-v’ to drop a new instance, the menu is quick, but key combos are quicker.