How to connect a rotary encoder to a BELA-enabled BeagleBone Black.

Hardware used in this post:

Connect rotary encoder Link to heading

The rotary encoder is connected to the digital pins on the BELA as shown in the figure below. The capacitors are used to do assure a minimum of debouncing.

SuperCollider Link to heading

I captured the data with SuperCollider running on my laptop. Encoding is done via UGens within the synthdef itself.

Preparation Link to heading

Start the server remotely, either by ssh’ing into the board or directly from within your SuperCollider IDE.

$ ssh root@192.168.7.2
bela$ scsynth bash -c 'scsynth -u 57110 -z 16 -J 8 -K 8 -G 16 -i 2 -o 2'
"ssh root@192.168.7.2 \"screen -dm -S scsynth bash -c 'scsynth -u 57110 -z 16 -J 8 -K 8 -G 16 -i 2 -o 2 > scsynth.log'\"".unixCmd

Initialise the server

Server.default = s = Server("belaServer", NetAddr("192.168.7.2", 57110));
s.initTree;
s.startAliveThread;

First steps Link to heading

First, listen to how the raw values coming from the pins can be used directly as amplitude envelopes for oscillators:

// simply listen to the pulses
Ndef(\a, {
  var trigs = DigitalIn.ar([0, 1, 2]); // A, B, button
  
  Splay.ar(SinOsc.ar([100, 800, 1900], 0, amps))
  
}).play;

The pulses of the pins can be interpreted as a 2bit gray-encoded number.

// convert gray code into binary values
Ndef(\a, {
  var pA = DigitalIn.ar(0);
  var pB = DigitalIn.ar(1);
  
  var gray = [pA, (pB * 2)].sum;
  // convert to standard binary encoding
  var bin = Select.ar(gray, DC.ar([0, 1, 3, 2]));

  // for every change in the signal, create a trigger
  var changed = Changed.ar(pA) + Changed.ar(pB);

  // poll whenever something changed  
  bin.poll(changed); //poll changes (output on bela!)
  
  SinOsc.ar(100 * (bin + 1)) * Decay.ar(changed, 0.2).tanh!2;
})
)

Integrate Link to heading

If only one update per click is required, the code can be simplified. Additionally, we compute the direction of turning and feed this into an integrator to get absolute value changes.

Ndef(\a, {
  var pA = DigitalIn.ar(0);
  var pB = DigitalIn.ar(1);

  var trig = HPZ1.ar(pA * pB) > 0;
  var sign = Delay1.ar(pA - pB);

  // sign.poll(trig, "sign");
  // trig.poll(trig, "trig");
  var note = Integrator.ar(trig * sign).poll(trig, "int");

  SinOsc.ar(note.midicps)!2;
})