Skip to content
A read-only fossil dump of Patchwerk.
C CWeb Lua Makefile C++ TeX
Branch: master
Clone or download
Pull request Compare This branch is 11 commits ahead of MuvikLabs:master.
paul
paul whitespace removal
FossilOrigin-Name: 712d9940d38478031ac932f6dd107b18d8e3ea5d0857e1fcc702d779de975c89
Latest commit 3aa12a2 Oct 12, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
dsp
examples
runt
LICENSE
Makefile
README.md
cable.w added checks to pw_cable_pop Jun 4, 2018
dump.w implemented initial data dumpers Mar 31, 2018
egraph.w
error.w negative bounds-checking as well Sep 17, 2018
header.w
macros.tex
memory.w migrated memory allocation to internal memory functions Aug 1, 2018
node.w
patch.w
patchwerk.w
pointer.w
pool.w
print.w
stack.w
subpatch.w

README.md

Patchwerk

What is it?

Patchwerk is a portable ANSI C library for constructing audio graphs and DSP signal chains. It designed to be portable, fast, and memory efficient. The core Patchwerk is written using the CWEB literate programming system.

In addition to the core patchwerk API, there is also an actively maintained Runt interface with a built-in collection of DSP nodes from Soundpipe. The goal this Runt interface is to provide a similar feeling and faster alternative to Sporth, a stack-based audio language previously created by the author.

Why was it created?

Patchwerk was built to be a better engine than Sporth. In most ways, this is true. It is much easier to introduce new modules than in Sporth. Patchwerk can often perform much better than the Sporth system as well.

Where does one get this?

Patchwerk is privately maintained as a Fossil repo, but a read-only git export can be found on github

How does it work?

The gist

Patchwerk produces audio graphs known as patches.

Patches are made up of interconnected things called nodes.

Nodes connect to one another with the use of cables.

All of this is managed using the patchwerk API.

Computation

Patchwerk computes audio one block at a time. A block size of 64 samples is used by default.

Nodes are executed sequentially in the order they are created. Since nodes can modulate other nodes, nodes can only make a connection if the node they are connecting to was created after itself. This simple rule solves the issue of dependency.

Cables and block memory

But wait! Things get a bit trickier. Patchwerk is a block-based system, meaning any cable that wants to be audio-rate needs to store things in a buffer. Every audio-rate cable could have allocated their own buffer, but this does not scale well from a memory standpoint, especially on constrained computing environments.

To make memory more manageable, Patchwerk implements a combination of a memory pool manage buffers. The memory pool has a pre-allocated set of buffers to choose from, which removes the scaling issue.

Stack-based interface

Buffers in the pool are consantly being overwritten and re-used. This is managed using a stack interface. Buffers pushed to the stack are immutable, and when they are popped, they return back to the pool to be reclaimed.

Highly serial patches (A to B to C), such as the ones you find in Sporth, lend themselves quite well to this approach. In fact, thinking in Patchwerk feels a lot like thinking in Sporth. Many Runt + Patchwerk patches look identical to Sporth code.

Buffer Holding

The buffer stack stops being useful when you have signals that need to modulate many different components. Stack operation would make this incredibly difficult to read.

The workaround for this is to explicitly hold the buffer to ensure it doesn't get reclaimed for the duration that it is needed, then explicitely un-hold the buffer so that it can be re-used.

For those reading this far down: buffer holding is the big gotcha in Patchwerk. If you do not unhold a previously held buffer, it will cause a certain kind of resource leak, which is troublesome if you want to recompile + hotswap patchwerk patches.

What kind of DSP modules does Patchwerk have?

By itself, none to speak of. One must define these externally. The runt patchwerk interface provides a default set of DSP routines via the soundpipe DSP library. With some work, one could easily write new DSP modules. With even more work, one could use FAUST to generate DSP code for patchwerk (this is doable).

You can’t perform that action at this time.