motion-induced blindness

a fascinating illusion. stare at the green dot for a bit.
more info here

this is just a remake of the wikipedia gif animation, but with the javascript code and its variables/settings it is open for experimentation.

<div style="background-color:black;">
<canvas id="can" width="600" height="600"></canvas>
//motion-induced blindness after
var rotationRate= 0.1;  //rps
var blinkRate= 2.5;  //Hz
var numCrosses= 7;
var numDots= 3;
var dotRadius= 5;
var crossWidth= 0.1;  //percent
var crossWeight= 3;
var colorBackground= '#000';
var colorCrosses= '#00F';
var colorCenter= '#0F0';
var colorDots= '#FF0';
var can, ctx;
(function() {
    can= document.getElementById('can');
    ctx= can.getContext('2d');
function draw() {
    var w2= can.width*0.5;
    var h2= can.height*0.5;
    var uw= can.width/3;

    ctx.fillStyle= colorBackground;
    ctx.fillRect(0, 0, can.width, can.height);

    ctx.translate(w2, h2);
    ctx.lineWidth= crossWeight;
    ctx.strokeStyle= colorCrosses;
    for(var i= 0; i<numCrosses; i++) {
        var y= i*(uw*2)/(numCrosses-1)-uw;
        for(var j= 0; j<numCrosses; j++) {
            var x= j*(uw*2)/(numCrosses-1)-uw;
            ctx.moveTo(x-(crossWidth*uw), y);
            ctx.lineTo(x+(crossWidth*uw), y);
            ctx.moveTo(x, y-(crossWidth*uw));
            ctx.lineTo(x, y+(crossWidth*uw));

    if ((*blinkRate)%1>0.5) {
        ctx.fillStyle= colorCenter;
        ctx.ellipse(w2, h2, dotRadius, dotRadius, 0, 0, Math.PI*2);

    ctx.translate(w2, h2);
    ctx.fillStyle= colorDots;
    for (var i= 0; i<numDots; i++) {
        ctx.ellipse(can.width/4, 0, dotRadius, dotRadius, 0, 0, Math.PI*2);


also attached is the same code ported to processing and supercollider.

Binary Data processing1.39 KB
Binary Data supercollider1.57 KB

keyboard shortcuts

macbook pro mid-2015 keyboard after some hard use of the cmd key. my habits shining through.

the left side shift and the three up/down/right arrow keys also have this nice transparency look. but strangely enough the left arrow key must not have been used much.

hid to osc

a human-interface-device (HID) to open-sound-control (OSC) converter for macOS written in Python3.

the program can send OSC to any IP and port but by default it will send to (localhost) on port 57120 (supercollider).

here is a binary build... (macOS, 64bit, 5.3mb)

to run it start and type...

cd ~/Downloads

that should list available HID devices on your system. after that you will probably see a warning that it failed to open the default device.

so to open and start reading data from any of your own devices you will need to give the correct vendor id and product id as arguments.

usage: HIDtoOSC [-h] [-V] [--vid VID] [--pid PID] [--ip IP] [--port PORT]
                [--rate RATE] [--debug]

optional arguments:
  -h, --help     show this help message and exit
  -V, --version  show program version
  --vid VID      set HID vendor id
  --pid PID      set HID product id
  --ip IP        set OSC destination IP
  --port PORT    set OSC destination port
  --rate RATE    update rate in milliseconds
  --debug        post incoming HID data

example - usb keyboard

here is an example that show how to connect to an external generic usb keyboard with the vendor and product id 6700, 2.

NOTE: for security reasons sudo is needed when accessing keyboards but not for accessing most other devices (gamepads, joysticks, mice)

some times you will need to run the program a few times before the HID is claimed. stop the program with ctrl+c

in the example the key A is pressed and released, but all HID will use their own data format. the --debug flag makes the program print out the incoming data.

receiving osc

then in SuperCollider we can receive the data as an OSC message. test it by running the line...


here is what the example above generates...

OSC Message Received:
        time: 75956.941459501
        address: a NetAddr(, 56073)
        recvPort: 57120
        msg: [ /hid, 6700, 2, Int8Array[ 0, 0, 4, 0, 0, 0, 0, 0 ] ]

example - usb mouse

and here is another example connecting to an optical mouse. (no sudo needed)

this example sends OSC to port 9999 and the data format is slightly different than in the keyboard example above.


if you do not trust the binary above (and you should not - specially when running it with sudo) you can run the python code directly.

homebrew and python3 is required.

first install some libraries...

brew install hidapi liblo

next create an virtual environment...

cd ~/python3
mkdir HIDtoOSC && cd HIDtoOSC
python3 -m venv env
source env/bin/activate  #to later leave the virtual environment type: deactivate

then install some python libraries...

pip install pyliblo
pip install hid pyusb
pip install pyinstaller

then finally copy the main python program below, put it in a file called and test it with for example python -h (stop with ctrl+c)

#f.olofsson 2019

# required python libraries: pyliblo, hid, pyusb
# example: sudo python --vid 6700 --pid 2 --port 12002 --debug
# note: macOS must be running this as root if the device is a keyboard

import sys, argparse
import usb.core, hid, liblo

version= 0.1

parser= argparse.ArgumentParser()
parser.add_argument('-V', '--version', action= 'store_true', help= 'show program version')
parser.add_argument('--vid', type= int, dest= 'vid', help= 'set HID vendor id')
parser.add_argument('--pid', type= int, dest= 'pid', help= 'set HID product id')
parser.add_argument('--ip', dest= 'ip', help= 'set OSC destination IP')
parser.add_argument('--port', type= int, dest= 'port', help= 'set OSC destination port')
parser.add_argument('--rate', type= int, dest= 'rate', help= 'update rate in milliseconds')
parser.add_argument('--debug', dest= 'debug', action= 'store_true', help= 'post incoming HID data')

parser.set_defaults(vid= 1452)
parser.set_defaults(pid= 517)
parser.set_defaults(ip= '')
parser.set_defaults(port= 57120)
parser.set_defaults(rate= 100)
parser.set_defaults(debug= False)
args= parser.parse_args()

if args.version:
  sys.exit('HIDtoOSC version %s'%version)

print('Available HID devices:')
for d in hid.enumerate():
  print('  device: %s, %s'%(d['manufacturer_string'], d['product_string']))
  print('  vid: %s, pid: %s'%(d['vendor_id'], d['product_id']))

def main():
  dev= usb.core.find(idVendor= args.vid, idProduct=

  if dev is None:
    sys.exit('Could not find device %s, %s'%(args.vid,

  for config in dev:
    for i in range(config.bNumInterfaces):
      if dev.is_kernel_driver_active(i):

  except usb.core.USBError as e:
    sys.exit('Could not set configuration: %s'%str(e))

  endpoint= dev[0][(0, 0)][0]
    dev= hid.Device(args.vid,
    print('Device %s, %s open'%(args.vid,
    sys.exit('Could not open device %s, %s'%(args.vid,

  target= (args.ip, args.port)
  noerror= True
  while noerror:
      data=, args.rate)
      noerror= False
        print('Closed the hid device')

    if data:
      if args.debug:
        print([x for x in data])
        msg= liblo.Message('/hid', args.vid,, ('b', data))
        liblo.send(target, msg)
        print('WARNING: Could not send osc to %s'%(target, ))

if __name__=='__main__':

later you can build your own binary with the command...

pyinstaller --onefile --hidden-import=libhidapi --add-binary='/usr/local/lib/libhidapi.dylib:.'


software written for and in collaboration with violinist George Kentros. premiered at after work - this violin must die, fylkingen stockholm 30 mar 2019.

the program is written in supercollider with additional features like ipad control and video mixer made in maxmspjitter.

main interface

the main window with its eight tracks (configurable) looks like this...

here you can set an amplitude threshold for the microphone and arm tracks to automatically detect and capture sounds.

with the waveform selection (dark grey areas) you select what part of the captured sound you want your different players to use.

there are many players - all with different behaviours...
slow, medium, repetitive, scanner, sweep, nervous, fastRhythmic, slowRhythmic, limpRhythmic, fast, drill, jump, plain, half, third, quarter, pingpong, crawl, wave, waveHalf, pattern1, pattern2, pattern3, round, sync

player behaviours include in which direction and how fast to progress in the captured sound buffer, when to play for how long, with which envelope and how loud, how much transposition, play in which audio channel etc etc.
some of these players are using granular synthesis techniques while others are scratching and jumping around in the sound buffer in more or less unpredictable ways. hopefully the names listed here above will give a hint of what players do to the sound.

all players are pieces of code. for example this the code for the scanner player...

SynthDef(\scanner, {|buf, amp= 1, start= 0, end= 1|
        var dur=;
        var pha=;
        var pos= pha*(end-start)+start;
        var add=;
        var fre=, 1, 1.1, 18)+add*;
        var snd=
      , 0.05),
      , 0.5),
        );\, '/pos', pos);\\,;
        snd=, \, 0.5, 0.5, 0.005, 0.01, EnvGate());\, snd);

and most players will look very similar to this. but there are also a few special ones like sync which just matches the playback position of the player in the track above.

in the main window one can also set track volume, bypass any global effects and read/write soundfiles.

the computer keyboard may be used for shortcuts quickly arming, playing and selecting what each track should play.

global control

there is also an additional control gui with global volume, effects, automation and record...

the three sliders delay, sustainer, distortion are just simple wet/dry control for global effects (that can be bypassed for each track using the bp button), while the other sliders freeze, fire, industry, chaos, air are more complex and control a bunch of effects and behaviours. for example freeze will take the sound from all players and smear it out by removing transients and pitch shifting copies of the sound up/down in octaves.

when the automation button is clicked, the program itself can start and stop tracks, change effects and vary a lot of other parameters in the code. the idea here is that the software should be able to run independently and generate interesting variations over long periods of time. also it should never go completely silent nor go wild and overload everything.

remote ipad interface

all the above can be viewed and controlled remotely from a tablet or a phone using a web browser. we programmed a look-alike gui patch with maxmsp and the mira externals. this patch talks to the supercollider interface over opensound control.

the interface here is even more ugly - specially the waveform display because the sound data had to be downsampled and kept at a low resolution to reduce wifi network traffic. also it was hard to fit everything on a single screen as all widgets had to be quite large and not too close to each other to be usable on an ipad.

our software also includes a video mixer for camera and movie playback (not shown here).

sc: fixed number of decimals

here's a quick function for displaying float numbers as strings in supercollider.

~fixDec= {|val, numDecimals= 2|  //float to string with fixed number of decimals
        var str= val.round(0.1**numDecimals).asString;
        var num= str.size-str.indexOf($.)-1;
        str.extend(str.size+numDecimals-num, $0);

//test examples
~fixDec.value(0.1, 3)
-> 0.100
~fixDec.value(0.12345, 3)
-> 0.123

//rounds internally.  compare:
~fixDec.value(0.191, 2)
-> 0.19
~fixDec.value(0.197, 2)
-> 0.20

//can deal with negative values
~fixDec.value(-2pi, 4)
-> -6.2832

//and integers
~fixDec.value(10000, 4)
-> 10000.0000

~fixDec.value(10000, 0)
-> 10000.


a much improved version of my old max application anneVideotracking

with this version you can use 12 zones on a webcamera video input to trigger midi, soundfiles, audio input (mics) and osc messages (send to supercollider for example).
the zones include filters and different types of thresholds and calibration. the data can be on/off triggers and or continuous values.

(sorry for the terrible gui design.)

download the mac standalone from here.

and here's the updated supercollider example that demonstrates how to use the osc data to control some sine oscillators.

//to start: select all & cmd+enter
//to stop: cmd + .
n= 12;
s.latency= 0.05;
        var dlast= 0.dup(n);
        d= {Bus.control(s, 1)}.dup(n);
        e= {Bus.control(s, 1)}.dup(n);
                var index= m[1], val= m[2], diff= (val-dlast[index]).abs;
                dlast.put(index, val);
        }, \anneVideoTracking);
        SynthDef(\annetest, {
                var src= Mix({|i|*100+400, 0,[i].index), 0.01, 0.1))}.dup(n));

midi pedals

here's how i built a usb foot pedal that sends out midi cc messages as well as note on/off messages when crossing some threshold.

to get a rugged pedal i bought a sewing machine foot pedal / speed control. for converting to midi and connecting to a computer i used a digispark module. the two other parts needed was a 3,5mm socket and a 4K7 resistor.



the code for the digispark is really simple and i programmed it from the arduino ide. THRESH_HI and THRESH_LO together with the state variable implements hysteresis, and lastVal is used to filter out any repeating values.

//with Digispark (Default - 16.5mhz)
//connect 4.7K resistor between tip and 5v, tip to P2 and sleeve to gnd

//usb yellow or red     5v
//usb white             data-
//usb green             data+
//usb grey or black     gnd

#define USB_CFG_DEVICE_NAME     'm','i','d','i','P','e','d','a','l'
#include <DigiMIDI.h>

#define PINLED 1      //onboard led
#define PINSENSOR A1  //foot controller sensor (P2)
#define PINGND 0      //ground
#define CTRL 7        //midi controller (cc)
#define NOTE 99       //midi note
#define VELO 64       //midi velocity
#define CHAN 9        //midi channel
#define THRESH_HI 100 //0-127
#define THRESH_LO 50  //0-127

DigiMIDIDevice midi;
int lastVal = 0;
int state = 0;

void setup() {
  pinMode(PINLED, OUTPUT);
  pinMode(PINGND, OUTPUT);
  digitalWrite(PINGND, LOW);
  midi.sendNoteOff(NOTE, VELO, CHAN);

void loop() {
  int val = analogRead(PINSENSOR);
  val = constrain(val, 9, 900);
  val = map(val, 9, 900, 127, 0);
  if (val != lastVal) {
    midi.sendControlChange(CTRL, val, CHAN);
    if (state == 0 && val > THRESH_HI) {
      midi.sendNoteOn(NOTE, VELO, CHAN);
      digitalWrite(PINLED, HIGH);
      state = 1;
    } else {
      if (state == 1 && val < THRESH_LO) {
        midi.sendNoteOff(NOTE, VELO, CHAN);
        digitalWrite(PINLED, LOW);
        state = 0;
    lastVal = val;

some supercollider test code...

MIDIIn.connectAll;\pedalCont, {|...args| [\pedalCont, args].postln}, 7, 8);
MIDIdef.noteOn(\pedalOn, {|...args| [\pedalOn, args].postln}, 99);
MIDIdef.noteOff(\pedalOff, {|...args| [\pedalOff, args].postln}, 99);


for another project i also made a 3d printed variant. this one is not so rugged and only acts as an on/off switch. it's based on Adafruit's USB_Foot_Switch_Controller but modified to fit a digispark.


arduino code for this discrete pedal (only note on/off)...

//with Digispark (Default - 16.5mhz)
//modified Adafruit's USB_Foot_Switch_Controller

#define USB_CFG_DEVICE_NAME     'm','i','d','i','P','e','d','a','l'
#include <DigiMIDI.h>

#define PINLED 1  //onboard led
#define PINSENSOR 2 //switch
#define NOTE 89  //midi note
#define VELO 64  //midi velocity
#define CHAN 9  //midi channel

DigiMIDIDevice midi;

int state = 0;

void setup() {
  pinMode(PINLED, OUTPUT);
  midi.sendNoteOff(NOTE, VELO, CHAN);

void loop() {

  if (digitalRead(PINSENSOR) == 0) {
    if (state == 0) {
      digitalWrite(PINLED, HIGH);
      midi.sendNoteOn(NOTE, VELO, CHAN);
      state = 1;
  } else {
    if (state == 1) {
      digitalWrite(PINLED, LOW);
      midi.sendNoteOff(NOTE, VELO, CHAN);
      state = 0;

openbci wifi shield diy

here is how i built my own wifi shield for the openbci cyton and ganglion boards. the total cost was less than €10.

see the schematics.

* 1 esp8266-12 module
* 1 esp8266-12 adapter
* 2 push buttons
* 3 blue leds
* 1 ncp1117 voltage regulator
* 1 jst connector
* some resistors and capacitors
* pin headers and a piece of veroboard

on the white adapter board i first removed the 0K resistor link in the middle (R2). then i cut the two tracks that run from VCC to the left hand side 10K resistor (R3). next i soldered on a ncp1117 on the back side (not visible in the photo) and finally added two 100nF caps.

then i mounted the esp+adapter on a vero board, added male pin headers and the other components and wires.



it looks very rough but works great. here are instructions on how to upload firmware and how to use it.


Subscribe to f0blog RSS