Weathervane - A Piece for Modular Synth, Laptop and DJ Controller

Weathervane is an experimental piece I wrote for DJ controller, laptop and modular synthesiser. What does that mean? Basically, the DJ controller is used to play the piece. Rotating the turntable clockwise plays one sound (the modular synth) and rotating it counter-clockwise plays another sound (an Ableton synth patch). The faster you spin, the faster the notes come out!

In case you are wondering, I chose the name as the sounds remind me of the gently fluctuating rotations of a weathervane

Listen to the full piece (performed live by me) via the SoundCloud link, and watch my friend Jack perform it via the YouTube link.

How does it work? The nitty gritty is explained below.

Firstly, the DJ controller generates MIDI data. A MIDI CC value is generated when the wheel is turned, and changes depending on the speed and direction of the rotation. This MIDI CC data is read by a patch I built in Max/MSP. The patch figures out what speed the turntable is spinning and in what direction. These parameters modulate, respectively, the rate that notes are played and the destination for the notes (modular synth or Ableton).

The first sounds you hear in the piece are generated by a simple Ableton synth patch. These notes are played at varying speeds as follows: MIDI notes are sent from Max to Ableton at rates depending on the turntable rotation.

The modular synth is "played" by an Arduino, connected to a laptop via USB and to the synth via modified patch cords. Depending on serial messages the Arduino receives from the Max/MSP patch, it generates 5V gate pulses at different rates (faster spinning = more frequent pulses). It does this using its digital pins, effectively triggering notes on the synth. The Arduino code for this is pasted below.

// Sketch to generate 5V gate pulses for triggering of modular synth envelope generators
// Serial communication between Max and Arduino board allows modulation of time between pulses

// time variables
float dt = 0;
float currTime = millis();
float elapsed=0;

// data to be read
float inData = 1;

void setup() { 
  Serial.begin(9600);
  Serial.flush();
  digitalWrite(2,LOW);
}

void loop() { 
  // read data, ignore spurious "-1" messages
  inData = Serial.read();
  if(inData < 1) inData = 1;

  // get change in time since "currTime" last set
  dt = millis() - currTime;
  elapsed+=dt;

  // write pin 2 HIGH for 10ms if serial data is valid
  if(elapsed < 10 && inData != 1) digitalWrite(2,HIGH);

  // write pin 2 LOW after 10ms
  if(elapsed > 10) {
    // reset time counter to zero
    if(elapsed > 3000/inData) elapsed = 0;
    digitalWrite(2,LOW);
  }
  // reset currTime
  currTime = millis();
  
 // (optional) display data received
 // if(inData != 1)
   Serial.println(inData);
}