I think this could be much nicer expressed in postfix notation, because I can never remember the precedence of C's bitwise operators...

Show thread

```
1 $ a » $ f » 3 * 7 & @ + & 0 > - @ 0 2 # [ 1 a @ 0 2 # ] + « 1 - @ 1 2 # [ @ 1 2 # ] $ @ 1 2 # ] & - 2 » : * 7 @ 0 2 # ] + » : * 7 @ 0 2 # ] + » @ 0 2 # [ @ 2 2 # ] : * @ 1 « f ^ $ 1 1 » & 0 1 2 # + * 4 a + @ 0 2 # ] + » f f 2 # & @ 3 2 # [ $ e » 3 & 3 = a « $ e » f 1 2 # & 5 5 2 # ^ c 0 8 3 # @ - * 0 f f f 4 # & + $ * e » $ f f f 3 # & 5 » 0 0 0 1 4 # $ & + & @ 2 2 # ] * 2 » @ 4 2 # [ @ 4 2 # ] 7 » @ 4 2 # ]6 » ~ ^ f f 2 # & @ 4 2 # [ 1 8» c 2 * 1 - + 3 / f f f f 4 # $ & * b : + » 7 & 5 * 7 & 1+ $ $ @ 2 * 1 - + * $ f » 7 & a + » * f & 4 « f f2 # : @ 2 2 # ] & - & @ 5 2 # [ $ a » 1 & 2 $ e » 3 & 2 = + $ e » 2 : @ * + & 1 » + $ * f f 2 # & @ 6 2 # [ f f 2 # @ 3 2 # ] @ 5 2 # ] 2 / ^ @ 6 2# ] 3 / + @ 4 2 # ] 4 / + &
```

The source code from the video upthread, converted to a hypothetical postfix notation.

Show thread

The more obscure parts in the syntax:
$ is variable t (increments at 8kHz)
@ is variable c (output channel, [0..1] for stereo)
n# pops n more values from the stack and concatenates them as hex nibbles in topmost/littlemost endian order
[ writes to a register/memory
] reads from a register/memory
: duplicates the top of the stack

The number of registers available is implementation defined, should have at least 16 * number of channels available so that the syntax @ n 2 # [ always gives a unique register (indexing must wrap around instead of crashing).

All values are 32bit words, which means time wraps around after 6.2 days. You can write longer compositions by using registers (which are preserved between invocations).

Untested as I have not implemented a compiler or interpreter for this yet, it may have typos or other transcription errors.

Show thread

I have an idea for an interpreter that would visualize the state of the stack underneath each opcode, each cell in the stack colour-coded according to a hash of the expression that it represents.

I also want to add more opcodes to the spec: x to swap the top two items, for example.

Later it would be cool to go first-order, to be able to define new opcodes and use them. Even later, higher order: push quoted user-defined code onto the stack and evaluate it in the context of other user-defined code. I guess that's something like Forth?

Show thread

Here's a mockup (without colours) of a hypothetical stack visualization.

Show thread

mockup has bugs (where did the 'a' go?) but in my defence I am not a comptuer

Show thread

possible keyboard layout for touchscreen interface

```
cdef +-«» $@
89ab */%! []
4567 &|^~ :x
0123 <>=? #
```

Show thread

Ctrl-U to toggle output between signed and unsigned bytes works now. Example where it makes a big difference: `tf&8-`.

Ctrl-O to select a file to load works to some extent, the listing is stretched/bad if there are too few or too many files or the file names are too short or too long etc etc, and input focus is a bit wonky (some events go to the code editor instead of the file list).

Show thread

the long hypothetical postfix source code has some typos and doesn't sound quite the same..

Show thread

woozy modulation

```
t4»tc»f&:13#*8»@+
ff13#&:~:0013#&?ff2#&
:~ff2#&*6»ff2#&
tff73#&*6»
t4*+
ff13#&:~:0013#&?ff2#&
```

line 1: set frequency of modulator
line 2: make it triangular
line 3: make it curved
line 4: increase its amplitude
line 5: add it to the carrier
line 6: make it triangular

I could do with Forth-like word definitions, as lines 2 and 6 are identical.

So far all my opcodes are single characters, adding longer names would mean having to add spaces everywhere or adding some special delimiters for long names (maybe `{name}`, I already have `(comments)`).

Show thread

Need to make a decision: stick with the current OpenGL/GLFW user interface (which has a faint hope of being ported to Android via GLFM), or drop it and go with ncurses (which would make text display and UI widgets much easier), or drop custom UI and go with minimal text pipe input for commands.

Need a custom UI instead of just "your favourite text editor" if I want to keep the live stack visualisation. Maybe the vis is not so important if I allow custom words to be (re)defined, because the modularity will make it easier to comprehend.

Show thread

Went with minimal text pipe input and spaces between words. This is turning into a .

The input is not yet delimited into blocks, so syntax errors sometimes break everything and you need to restart from scratch.

Local argument declaration lists seem work in my brief test:

```
: audio { c t -- o } t 56 c 3 * + << ;
```

plays two sawtooth waves, the right channel 3 octaves higher than the left.

The 56 is there because the default type is now `int64_t`, and I haven't added casting operators yet (casting to `i8` or `u8` at the end would yield the traditional bytebeat variations).

So far it's dynamically typed, but I want to make it statically typed so I can catch errors earlier. This would mean I would need type annotations for argument lists, will research existing Forth-like syntaxes for that.

Words can be redefined, and I implemented a garbage collector for the dictionary to clean up old words, with a busywait() hack to avoid freeing words in case the audio thread is still executing them. But I haven't tested it out yet.

Show thread

I made all words deferred for more convenient live coding, makes recursion easier too.

The left stack (for regular evaluation) is fine, but the right stack (for local variables) overflows. The crash is because the C stack in the interpreter overflows too. The negative numbers are from signed integer overflow.

```
: fibs { a b -- b a+b } a . cr b a b + fibs ;
0 1 fibs
0
1
1
2
3
5
8
13
...
5167068349195539697
5957444661174968386
-7322231063339043533
-1364786402164075147
-8687017465503118680
8394940206042357789
ERROR: stack overflow
ERROR: stack overflow
-292077259460760891
ERROR: stack overflow
ERROR: stack overflow
8102862946581596898
Segmentation fault
```




Show thread

Worked on type inference for a bit, but I rushed it and didn't take care about memory ownership, so it was crashing all over and I couldn't debug it. What a waste. Maybe I'll prototype it in Haskell and port to C if I get it working.

Probably I was too ambitious going straight to inference/unification instead of just checking that the type annotations are consistent, and requiring more annotations if they are ambiguous.

Traditional Forth has no overloading, using `+` for int and `f+` for float etc.

My current working implementation has dynamic dispatch in the primitives based on the tagged unions that are on the stack, which does too much work at runtime and not enough at compile time.

Show thread

Converted the README.md to HTML with `pandoc` and tweaked the CSS slightly. mathr.co.uk/barry/

Show thread

long 

This version is tested and works. Splitting it up into separate word definitions was essential for debugging, using immediate mode to check for stack underflow / overflow.

```
: dup { a -- a a }
a a
;

: swap { a b -- b a }
b a
;

: Depth { c t -- kd }
t 15 >> 3 * 7 & c +
t 10 >> & 0 >
1 swap -
;

: Mask { kd -- km }
1 10 kd + << 1 -
;

: Env { kd km t -- e }
km t km & - 2 >>
dup * kd 7 + >>
dup * kd 7 + >>
;

: Kick { kd e c t -- kick }
e dup *
c 1 << 0xF ^ t 11 >> & 16 +
*
4 10 kd + + >>
0xFF &
;

: K { e c t -- k }
t 14 >> 3 & 3 == 1 + 10 <<
t 14 >> 0x1F & 0x55 ^ 0x80C c - * 0xFFF0 &
+
t * 14 >>
t 0xFFF & 5 >> t 0x1000 & +
& e * 2 >>
dup 7 >> swap 6 >> ~ ^
0xFF &
;

: A { e c t -- a }
1 8 << 2 c * 1 - + 3 / t 0xFFFF & * 22 >>
7 & 5 * 7 & 1 +
t t 2 c * + 1 - *
10 t 15 >> 7 & + >>
* 0xF & 4 << 0xFF dup e & - &
;

: Bass { c t -- bass }
t 10 >> 1 &
t 14 >> 3 & 2 ==
t 14 >> 2 dup c * + & 1 >>
2 + + t * *
0xFF &
;

: Thumper { c t | kd km e kick k a bass mixdown -- o }
c t Depth -> kd
kd Mask -> km
kd km t Env -> e
kd e c t Kick -> kick
e c t K -> k
e c t A -> a
c t Bass -> bass

kick a 2 / ^ 2 / bass 3 / + k 4 / +
0xFF &
-> mixdown

mixdown
;

: audio { c t -- o }
c t Thumper u8
;
```

Show thread

long 

@mathr Lots of small word definitions seems to be the Forth way of doing things. Are you writing a Forth parser for this?

long 

@paul I have a parser/compiler/interpreter thing I made that can run it but it's not exactly Forth (yet)

code.mathr.co.uk/barry

It will probably get more Forth-like and less adhoc-custom-hackery as it progresses.

Sign in to participate in the conversation
post.lurk.org

Welcome to post.lurk.org, an instance for discussions around cultural freedom, experimental, new media art, net and computational culture, and things like that.