Wishful Coding

Didn't you ever wish your computer understood you?

Making a new music instrument

A while a go I sent a message to Martin from Wintergatan that I want to help with the second version of his Modulin that he briefly talked about during one of his Marble Machine X videos.

He never replied, so I just decided to play around with my own ideas. The immediate goal is not so much to design a music instrument as it is to play around with touch input, digital signal processing, and analog filters.

For my first instrument I decided to build a chiptune violin by using a Game Boy as the synthesizer.

Step one was to figure out touch input. At first I wanted to do capacitive touch, but sensing position is not as easy as it’s made out to be. Then I found these SoftPot lineair potentiometers, which seem pretty good. At first I thought I would need a separate sensor strip to sense pressure, but by pressing down, a small track section of the SoftPot is shorted, resulting in a smaller total resistance that can be measured.

After playing with the Game Boy sound registers in the simulator for a while, I made a new copy of GALP for all the boilerplate code, then I added the following snippet to read an address and a byte from the Game Link port and simply write it to hiram. This code basically allows changing any register at all, not just the sound ones. The full code lives here.

; enable sound
  ld a,%10000000 ; enable
  ldh [rAUDENA],a
  ld a,$ff ; all channels
  ldh [rAUDTERM],a
  ld a,$77 ; max volume
  ldh [rAUDVOL],a

.loop

  call SerialTransfer
  ldh a,[rSB] ; new address
  ld c, a
  call SerialTransfer
  ldh a,[rSB] ; new data
  ld [$FF00+c],a ; write register
  jr .loop
  
SerialTransfer:
  ld a, $80 ; start external transfer
  ldh [rSC], a
.transferWait
  ldh a,[rSC]
  bit 7, a ; is transfer done?
  jr NZ, .transferWait
  ret

Then I connected the SoftPot to an Analog input of an Arduino with a 100k pull-down, and connected the Arduino SPI pins to the Game Link port. The code then simply reads the analog pin and sets the correct sound register on the Game Boy to play the corresponding note. The full code lives here.

int oldValue = 0;
void loop() {
      int sensorValue = analogRead(A9);
      bool lowValue = sensorValue < 1;
      bool oldLowValue = oldValue < 1;
      int outputValue = map(sensorValue, 0, 1023, 440, 1760);
      int oldOutputValue = map(oldValue, 0, 1023, 440, 1760);
      if(!lowValue && oldLowValue) { // rising edge
        ch2Length(63, 2);
        ch2Envelope(15, 0, 0);
        ch2Play(outputValue, 0, 1); 
      } else if (lowValue && !oldLowValue) { // falling edge
        ch2Envelope(15, 3, 0);
        ch2Play(oldOutputValue, 0, 1);
      } else if(!lowValue) { // high
        ch2Play(outputValue, 0, 0); 
      }
      oldValue = sensorValue; 
      delay(10);
}

The current code does not sense pressure and just uses a square wave channel on the Game Boy with an envelope on release. Next items on the list of things I want to try are sensing pressure and playing with some bucket brigade chips that have been sitting in my drawer.

Pepijn de Vos

Building Bad Amplifiers

My brother scavenged and repaired an old bass guitar, and asked if I could make him an equally bad amplifier to go with it to create the ultimate bad sound.

I was happy to oblige, so I threw everything I know about good amplifiers out of the window and googled around for some inspiration. Thus resulted in a lot of badly designed amplifiers, that subject your speaker to DC currents or don’t deliver any power at all.

So I started making some myself. First thought was to make a class A amplifier with a single power MOSFET and power resistor. I got two 1 Ω resistors in series, rated for 5 W. This gives a maximum voltage of 2.2 per resistor.

The MOSFET is rated for 30 A, so that’s probably fine. Then I used a potentiometer to bias the gate and a capacitor to drive it. Something like this.

class a

Problem is, while it’s a very nice and simple space heater, it does’t sound bad enough. It’s inefficient and non-linear, but the sound is kind of fine.

So the next step was to make an amplifier that sounds worse. What better than a pure class B output stage with its sweet unmitigated crossover distortion?

I pulled a complementary pair of BJTs from a drawer, and drove it with some random small-signal MOSFET and a 1K resistor. A diode was added to reduce the cross-over a bit. The output cap is just a large one. At the bottom of the MOSFET I added a 100 Ω degeneration resistor that I bypassed in AC with a capacitor for more gain. I again added a potentiometer to bias the MOSFET.

My brother liked the bad sound, but it wasn’t loud enough, so I added another MOSFET gain stage. Same story, 1K resistor, small bypassed degeneration resistor, and a potentiometer to bias the MOSFET. Except now I put the potentiometer as the degeneration resistor, for no good reason.

class b

Neither of these amplifiers involved much design, calculation, or simulation. They were directly constructed on overboard with potentiometers where I would have needed math to find the correct value, and I just made these drawings for this post.

Normally what you’d do is calculate the gate voltage created by the voltage divider.

The voltage across the degeneration resistor is then roughly

For a BJT the threshold voltage is roughly 0.6 V while a small-signal MOSFET is more like 2 V. Ohms law then gives you the current through the degeneration resistor, which is the same current as through the 1k resistor at the top, so you know how much voltage drops across that one.

Pepijn de Vos

Behavior Trees are Concatenative Programs

I have previously talked about how I got pulled into building soccer robots at Roboteam Twente. During the summer holiday I spent a lot of time thinking about their code and about ways to improve it. During this time I wrote 3 different behavior tree implementations, and stumbled upon something that I’ve not seen in any of the literature on behavior trees. (Behavior trees are basically state machines on steroids)

The main problem I was trying to solve is that over time, the leaf nodes that should contain the “how” in a tree of “what” had gotten increasingly large and complex, and it was desired to split those up in smaller tasks.

Behavior tree - C++ language barrier

Another related problem was that these leaf nodes, or skills as we call them, are basically untestable because they touch a lot of global mutable state and do a bunch of IO.

mutable state behavior tree

I believe these skills became so large and complex because the smaller skills that live inside them have complex interdependencies that cannot be easily expressed in behavior trees. There is not really a good way for these nodes to pass parameters around.

The conventional method for sharing information between skills is using “blackboards”, which are more like “inverse blackboards”, where rather than one person sharing information with the whole room, everyone is running around chalking random stuff all over the board.

So my first implementation applied some basic functional programming. All our skills look basically the same, get the world state, do some logic, and send messages. So I simply made all the nodes take the world state and return a list of messages.

functional behavior tree

However, this seemed way too specific, and did not really solve the problem of passing parameters around between nodes. Once I had generalized the list of messages to a parameter stack, the realization struck me that I was doing concatenative programming! I repeat:

Behavior Trees are Concatenative Programs

The idea that I was basically building a domain-specific stack-based concatenative programming language lead to a boatload of new ideas and implementation methods.

I particularly liked the way Forth has this hybrid between compiling and interpreting that allows very efficient yet very interactive programming. I also took a long, hard look at how Joy formalized statically typed concatenative programming in a purely functional way.

My second implementation was in Clojure, and I was delighted by how short and expressive it is. I will repeat my FizzBuzz implementation as a behavior tree below, where you pass in a number, and it returns a number or a string.

(defn fizzbuzz [n]
  (-> {}
    (spush n)
    (selector
      #(sequential %
          (modn 15)
          (message "FizzBuzz"))
      #(sequential %
          (modn 3)
          (message "Fizz"))
      #(sequential %
          (modn 5)
          (message "Buzz")))
    speek))

Seeing how the Clojure implementation played out, I doubled down on the concatentative programming language, and started work on an actual compiler for my DSL.

The third implementation is an actual compiler that fulfills most of my Joy aspirations. It compiles a statically typed Forth-like language to C code, where you can easily implement new words in C.

There is no explicit stack or API for defining words. I parse your C headers for compatible functions, and compile your Bobcat code to a series of function calls on regular C stack variables.

There is no conventional control flow in Bobcat. It has quotations (which compile to function pointers), and special forms for function definition and – importantly – interpreting a quotation as a behavior tree node, which adds the necessary control flow to implement all the usual behavior tree nodes (sequential, selector, etc.) as C functions.

One noteworthy feature is that there is actually a separate stack per type. I think this is a good trade-off for a DSL, compared to the homogeneous stack of words seen in most stack-based languages. This limits your ability to have generic words like swap and dup, but allows dealing with many things, without too much stack juggling. Those details are mostly handled in the host language.

A funny detail I implemented is the comma operator, which is like executing words in parallel. Much like Clojure’s juxt.

As a small example, something simple like 2 dupi addi 5 muli will compile to the following (which GCC can basically optimize to *out_0=20)

void test(int *out_0)
{
  int var_1 = 2;
  int b_1;
  int c_1;
  dupi(var_i, &b_1, &c_1);
  int c_3;
  addi(c_1, b_2, &c_3);
  int var_2 = 5;
  muli(var_2, c_3, &c_e);
  *out_0 = c_5;
}

With something like dupi simply defined as

void dupi (int const a, int* b, int* c) {
    *b = a;
    *c = a;
}

What is sill missing is a more powerful way to work with quotations, which are at the moment useless and broken outside of function definitions and behavior tree nodes. And a really big omission in this design is interactive programming. I want this quite badly, so maybe some day there will be a fo(u)rth implementation, which will be more like Forth.

But for now, I’ve started my masters and a new job, so I had to put a halt to this development. However, I still think this is a powerful concept that will allow writing more expressive, small, testable behavior trees.

Pepijn de Vos