double densed uncounthest hour of allbleakest age with a bad of wind and a barrel of rain
double densed uncounthest hour of allbleakest age with a bad of wind and a barrel of rain is an in-progress piece for resonators and brass. I’m keeping a composition log here as I work on it.
As of March 2025, I’m writing about other things here too.
Saturday July 26th
One of the early choices in pippi was the question of how to deal with different types of buffer abstractions. The earliest versions of pippi followed the design of the python standard library: all buffers were just byte strings. [0] That was a really cool choice for the python 2 era. String manipulation even then in python was actually pretty fast, but more importantly the facilities for slicing and dicing strings in pure python were very ergonomic. Even though 16 bit stereo audio had to be packed across 2 bytes and 2 samples and it was easy to slice into a sound string in the wrong place and blow up the audio in fun ways, with some helper functions to slice in the right places it was actually pretty nice for doing microsound work.
Natively microsound
That was the start of an obsession, since I found reasoning about microsound composition in unit-generator environments difficult to the point of driving me to want to create a system based around python’s comfortable string slicing and dicing interfaces. [1]
Abstraction is tough
Abstraction is a hard balance to strike. Bags of bytes like python’s byte strings (or an array of chars in C, whatever) are simple and flexible, but the noise in usage can build up enough that it makes sense to add a layer of abstraction on top. For example, python bytes strings already embed their lengths. That small convenience makes a bigger difference to expressiveness than it might seem. Carrying around a length in a side channel (now every element of the composition has two parts to manage) manually everywhere in a composition is more error-prone and tedious than embedding that value in the string itself. Knowing that new substrings extracted from a string will have their lengths updated correctly without having to think about it lets you worry more about the things that matter, rather then dealing with bookkeeping issues.
So, it was that mindset that led me to create three basic types in
pippi exposed at the python level: SoundBuffer
for
unbounded multi-channel sounds, Wavetable
for
single-channel / linear / flat data that was also symmetrically
unbounded (in other words, signals from -whatever to +whatever
oscillating around a zero point like you’d use in a wavetable osc) and
Window
for single-channel / linear / flat data with bounds
between 0 and 1, useful for windowing functions, etc.
It seemed like a nice idea to be able to check the type of some
buffer to know its contents, and fill buffers simply by saying things
like sine
or tri
knowing that a
sine
argument to a Wavetable
constructor would
produce a full period of a sinewave, while the Window
constructor would simply use the first half.
from pippi import dsp
'sine').graph('win-sine.png')
dsp.win('sine').graph('wt-sine.png') dsp.wt(


Simplifying
A decade later, I’ve changed my mind. It’s a big refactoring project,
but I think the next step for buffers in pippi is to simply collapse
everything into SoundBuffer
s, and provide nice interfaces
for filling them with the sorts of data needed, and doing basic
introspection on their contents as needed.
For example, nothing about the above interfaces in pippi need to
change, the dsp.wt
and dsp.win
routines would
simply return a single channel SoundBuffer
filled in the
appropriate way rather than a special Window
or a
Wavetable
type. There were already some basic introspection
options on the old buffers, but the new buffers have a slightly more
expanded set allowing a simple way to get the minimum, maximum, average,
magnitude (absolute value maximum, useful for symmetric signals), etc as
needed.
From numpy ndarrays to
lpbuffer_t
Last night I clobbered my way through the last parts of a related
(and larger) refactoring project I’ve been working on for years. I
wasn’t expecting to get as far on it as I did, but found myself
barreling through and ripping out the old buffers finally. Pippi
SoundBuffer
s are now backed by libpippi
lpbuffer_t
structs, which are both simpler and also have a
few extra slots for metadata to make using them like ringbuffers, etc a
little easier. They’re exposed to python through the buffer protocol and
a reworked version of the cython class interface of the previous
numpy-backed buffers. [2]
In C-land, libpippi lpbuffer_t
buffers are already the
main data structure for all sound buffers. There is an internal
lparray_t
for integer bags, and a concept of “stacking”
buffers that I haven’t really settled on a final version of yet, but
lpbuffer_t
is the primary data structure for almost
everything. Since the new SoundBuffer
s in pippi all use the
libpippi routines, collapsing the Wavetable
and
Window
abstractions into them should be more
straightforward than trying to do this with the older buffers, where all
transformations were more specialized across the three types.
Getting there
The major projects in this next refactor are basically:
- Add all the interfaces unique-to-wavetables-and-windows into the
SoundBuffer
s, for exampleskew()
which does phase distortion. - Finish adding all the older cython built-in wavetables and window types to libpippi. (I’ve only implemented a core set of basic types, but one day into using the new interface I already really miss the more esoteric built-in shapes.)
There is never a good time for these projects… but since I’m already cleaning up this larger refactor over the weekend, I think this is probably the right time to take a moment to work on wavetables / windows again too. I hope I can finish it all before the fall, when I have a few musicing things planned. Pippi is more crashy again right now, but still stable enough for jazz. I’d like to smooth the edges over more significantly this summer though.
[0] Or put another way, since this was the python 2 era where all strings were byte strings – meaning one character simply equals one 8 bit byte, and all strings are C-like sequences of raw bytes or ASCII chars, rather than one character being a unicode code point made up potentially of several bytes)
[1] Some years later I read Hiroki Nishino’s Unit-generators considered harmful (for microsound synthesis) and felt way less alone on this journey!
[2] In other words, in python it should be relatively simple to mix and match numpy arrays and pippi
SoundBuffer
s. This has always been possible because internally the older buffers exposed aframes
property which was just the raw numpy array, but it was fairly clunky in practice and required some more manual work. The driving force behind that project was to reduce copies (libpippi buffers can be shared with C threads more easily without copies) and make the numpy dependency for the project optional. That also shows the age of this refactoring project: when I started, installing numpy was a legitimately difficult thing to do in many environments. The situation has changed for the better though! I don’t feel the need to ditch numpy entirely anymore, really. Still the tweaks to theSoundBuffer
interface that came out of this refactor are a step in the right direction, I think.
Friday July 11th
Pippi’s new licence agreement.
From 616b1f64c68585e8cc52fbf6cdb08077795278f5 Mon Sep 17 00:00:00 2001
From: Erik Schoster <erik@hecanjog.com>
Date: Fri, 11 Jul 2025 02:52:45 -0500
Subject: [PATCH] update license terms
---
LICENSE | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/LICENSE b/LICENSE
index c43bef0c0812cd81287c4b584455aa7bce37b626..09beed8a18e9137554e2520c738d89db523acd88 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1 +1,9 @@
-Do anything you like with this software. Be nice. Make many things. :-)
+Take a deep breath. Ask yourself, what are you building and why are you building it?
+
+Is it something that seems interesting or useful or fun?
+
+Or is the point to try to dupe someone out of their money?
+
+If it's the latter, then fuck off.
+
+Otherwise do whatever you find interesting and rewarding with this software.
Log June 2025
Log May 2025
Log April 2025
Log March 2025
Log February 2025
Log January 2025
2024 and earlier