8f4e

8f4e is a stack-oriented programming language designed for real-time audio synthesis, with a visual code editor built for live coding and experimentation.

I started it as a recreational programming project during the COVID-19 lockdown to perform generative music at algorave events.

Its primary target is the WebAssembly virtual machine, as I wanted an efficient yet portable tool for real-time audio signal generation and processing.

Stack-oriented programming

Stack-oriented programming means that instead of using registers, instructions take their operands from a stack and push their results back onto the same stack for the next instruction to consume.

I chose this programming paradigm because the WebAssembly virtual machine is itself a stack machine.

Staying native to this execution model avoids costly abstractions and makes it possible to write faster programs compared to typical WebAssembly-targeting languages.

...
021 push 2
022 push 3
023 ; Pushing values 2 and 3
024 ; onto the stack.
025 add
026 ; After executing the
027 ; add instruction,
028 ; the stack will contain
029 ; the value 5
030 push 10
031 mul
032 ; Now the stack will
033 ; contain the value 50
034 push 10
035 div
036 ; Now 5 again
...

Memory access and pointers

Unlike in most programming languages, memory addresses in 8f4e are determined by the compiler and inlined at compile time.

This allows direct memory access with pointers, without requiring an additional indirection layer such as a heap or garbage collector.

...
021 int result
022 push &result
023 ; The variable name
024 ; prefixed with &
025 ; gives its memory address.
026 push 42
027 store
028 ; The store instruction
029 ; takes two values:
030 ; a memory address
031 ; and the value to store.
...

Sequential memory layout

All memory items are laid out sequentially in memory, so variables declared one after another occupy adjacent memory locations.

They are aligned on a 32-bit grid, which means every memory item starts at an address that is a multiple of 4 bytes.

...
021 int   a 42
022 
023 float b 3.14
024 ; Memory address of b
025 ; is address of a + 4
026 
027 int   c -5
028 ; Memory address of c
029 ; is address of b + 4
...

Live variable editing

8f4e supports real-time editing of variable values while a program is running, without recompilation.

This is made possible by the deterministic allocation strategy: because memory addresses are fixed at compile time, the compiler can provide the exact address of every memory item, allowing the editor to locate and update any variable directly.

...
021 int foo 10
022 ; You can change these
023 ; values in the editor
024 ; while the program is running.
025 float bar 3.14
026 ; The editor will trace
027 ; them back in the memory
028 ; and update their values
029 ; without restarting
030 ; or recompiling the program.
...

Modules and execution order

The code is organized into modules, each containing variable declarations and a sequence of commands.

The execution order of the code modules is determined by their dependencies. If a module's output is needed as input for others, it is executed first.

...
021 module foo
022 
023 int  a 10
024 int  b 20
025 int  result
026 
027 push &result
028 push a
029 push b
030 add
031 store
032 
033 moduleEnd
...

Public variables and pointer iteration

All variables in 8f4e are inherently public, with no option to modify visibility.

8f4e is not memory-safe, pointers can point to anything within the memory space of the program, but the visual wires help developers to find where their pointers are pointing.

...
021 int* pointer
022 
023 push &pointer
024 push pointer
025 push 4
026 push add
027 store
028 ; pointer will iterate through
029 ; memory in 4-byte steps.
...