Attack Of The Dronez.


A technical description of an experimental music piece by Alwyn Nixon-Lloyd

Performed:
The sections below are:


Overview


AotD is a piece that was driven by the theme for NoizeMaschin #72 which was "Chiptune Special".
Because of the "chiptune" theme, the main part of the piece is the three 8-bit processor based Arduinos.  Two of them are creating a drone.  The third is acting as a very short reverb and waveshaper, used for the feedback path of the mixer.







Parts and Patching

The parts used were:
The signal path in the Zoom  was Uni-Vibe -> Octaver -> Gain Booster






Performance Controls


The system has a number of performance inputs to control the sound. On the Behringer Mixer, each channel has: The Pan control was not used, as only the Left output of the mixer was used
The ZOOM has it's own internal patch, consisting of the UniVibe emulation, Octaver and Gain. Only the controls of the UniVibe emulator were used. The controls used were:
The Eventide Time factor is put on the output of the mixer before going to the PA. It was set to a modulated delay mode with heavy modulation, but a very low mix level, to add some additional depth to the sound.



Code

The Code for the Arduinos is below.
Ardunio #1 and #2 ran code that generated converging sine oscillator tones.   The difference between #1 and #2 are the starting and ending frequencies for the tones.

Ardunio #3 ran a short reverb program.
Some notes:
/**
 *   Sketch_jun26d  AotD drones #1
 *   must be compiled with USE_AUDIO_INPUT disabled
 */
#include <MozziGuts.h>
#include <Oscil.h>
#include <tables/sin2048_int8.h> // sine table for oscillator
#include <mozzi_fixmath.h>
#include <Line.h>
#include <WaveShaper.h>
#include <tables/waveshape_compress_512_to_488_int16.h>

#define CONTROL_RATE 64 // powers of 2 please

// 2 oscillators to compare linear interpolated vs smoothed control
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin0(SIN2048_DATA);  //F1
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> bSin0(SIN2048_DATA);  //F2
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> cSin0(SIN2048_DATA);  //F3
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> dSin0(SIN2048_DATA);  //F4
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> eSin0(SIN2048_DATA);  //F5
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> fSin0(SIN2048_DATA);  //F6
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> gSin0(SIN2048_DATA);  //F7
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> hSin0(SIN2048_DATA);  //F8
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> iSin0(SIN2048_DATA);  //F9
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> jSin0(SIN2048_DATA);  //F10

WaveShaper <int> aCompress(WAVESHAPE_COMPRESS_512_TO_488_DATA); // to compress instead of dividing by 2 after adding signals

Line <Q16n16> aInterpolate;
Line <Q16n16> bInterpolate;
Line <Q16n16> cInterpolate;
Line <Q16n16> dInterpolate;
Line <Q16n16> eInterpolate;
Line <Q16n16> fInterpolate;
Line <Q16n16> gInterpolate;
Line <Q16n16> hInterpolate;
Line <Q16n16> iInterpolate;
Line <Q16n16> jInterpolate;

// the number of audio steps the line has to take to reach the next control value
const unsigned int AUDIO_STEPS_PER_CONTROL = 64;//AUDIO_RATE / CONTROL_RATE;
const int FIVE_MINS = CONTROL_RATE*5*60;

int runtime =0;
float f1_freq;
#define F1START 22.5f
#define F1END 110.1f
#define F2START 10.f
#define F2END 220.f
#define F3START 440.f
#define F3END 110.2f
#define F4START 880.f
#define F4END 109.9f
#define F5START 28.f
#define F5END 110.01f

#define F6START 165.f
#define F6END 111.1f
#define F7START 330.f
#define F7END 109.21f
#define F8START 999.f
#define F8END 109.5f
#define F9START 345.f
#define F9END 109.91f
#define F10START 550.f
#define F10END 55.1f


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  runtime = 0;

  //set up frequency lines
  aInterpolate.set(float_to_Q16n16(F1START),float_to_Q16n16(F1END),FIVE_MINS);
  bInterpolate.set(float_to_Q16n16(F2START),float_to_Q16n16(F2END),FIVE_MINS);
  cInterpolate.set(float_to_Q16n16(F3START),float_to_Q16n16(F3END),FIVE_MINS);
  dInterpolate.set(float_to_Q16n16(F4START),float_to_Q16n16(F4END),FIVE_MINS);
  eInterpolate.set(float_to_Q16n16(F5START),float_to_Q16n16(F5END),FIVE_MINS);
  fInterpolate.set(float_to_Q16n16(F6START),float_to_Q16n16(F6END),FIVE_MINS);
  gInterpolate.set(float_to_Q16n16(F7START),float_to_Q16n16(F7END),FIVE_MINS);
  hInterpolate.set(float_to_Q16n16(F8START),float_to_Q16n16(F8END),FIVE_MINS);
  iInterpolate.set(float_to_Q16n16(F9START),float_to_Q16n16(F9END),FIVE_MINS);
  jInterpolate.set(float_to_Q16n16(F10START),float_to_Q16n16(F10END),FIVE_MINS);

  startMozzi(CONTROL_RATE); 
}

void updateControl(){

    if(runtime % 64 ==0){
      Serial.print("runtime \t");Serial.println(runtime); 
    }
    //if we have ended.
    if(runtime > FIVE_MINS){
      aInterpolate.set(float_to_Q16n16(F1END),float_to_Q16n16(F1END),FIVE_MINS);
      bInterpolate.set(float_to_Q16n16(F2END),float_to_Q16n16(F2END),FIVE_MINS);
      cInterpolate.set(float_to_Q16n16(F3END),float_to_Q16n16(F3END),FIVE_MINS);
      dInterpolate.set(float_to_Q16n16(F4END),float_to_Q16n16(F4END),FIVE_MINS);
      eInterpolate.set(float_to_Q16n16(F5END),float_to_Q16n16(F5END),FIVE_MINS);
      fInterpolate.set(float_to_Q16n16(F6END),float_to_Q16n16(F6END),FIVE_MINS);
      gInterpolate.set(float_to_Q16n16(F7END),float_to_Q16n16(F7END),FIVE_MINS);
      hInterpolate.set(float_to_Q16n16(F8END),float_to_Q16n16(F8END),FIVE_MINS);
      iInterpolate.set(float_to_Q16n16(F9END),float_to_Q16n16(F9END),FIVE_MINS);
      jInterpolate.set(float_to_Q16n16(F10END),float_to_Q16n16(F10END),FIVE_MINS);
      Serial.println("end line");
      //probs should turn on red LED here.    
    }

    aSin0.setFreq_Q16n16(aInterpolate.next());
    bSin0.setFreq_Q16n16(bInterpolate.next());
    cSin0.setFreq_Q16n16(cInterpolate.next());
    dSin0.setFreq_Q16n16(dInterpolate.next());
    eSin0.setFreq_Q16n16(eInterpolate.next());
    fSin0.setFreq_Q16n16(fInterpolate.next());
    gSin0.setFreq_Q16n16(gInterpolate.next());
    hSin0.setFreq_Q16n16(hInterpolate.next());
    iSin0.setFreq_Q16n16(iInterpolate.next());
    jSin0.setFreq_Q16n16(jInterpolate.next());
    
    runtime++;
}

int updateAudio(){

  int snd = (int)(aSin0.next()+bSin0.next()+cSin0.next() + dSin0.next() )>>2;
  int snd2 = (int)(eSin0.next() +fSin0.next() +gSin0.next()+hSin0.next() + iSin0.next() + jSin0.next())>>3;

  return aCompress.next(256u + snd + snd2);
 }


void loop() {
  // put your main code here, to run repeatedly:
  audioHook();
}



  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/**
 *   Sketch_jun26e  AotD drones #2
 *   must be compiled with USE_AUDIO_INPUT disabled
 */

#include <MozziGuts.h>
#include <Oscil.h>
#include <tables/sin2048_int8.h> // sine table for oscillator
#include <mozzi_fixmath.h>
#include <Line.h>
#include <WaveShaper.h>
#include <tables/waveshape_compress_512_to_488_int16.h>

#define CONTROL_RATE 64 // powers of 2 please

Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin0(SIN2048_DATA);  //F1
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> bSin0(SIN2048_DATA);  //F2
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> cSin0(SIN2048_DATA);  //F3
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> dSin0(SIN2048_DATA);  //F4
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> eSin0(SIN2048_DATA);  //F5
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> fSin0(SIN2048_DATA);  //F6
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> gSin0(SIN2048_DATA);  //F7
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> hSin0(SIN2048_DATA);  //F8
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> iSin0(SIN2048_DATA);  //F9
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> jSin0(SIN2048_DATA);  //F10

WaveShaper <int> aCompress(WAVESHAPE_COMPRESS_512_TO_488_DATA); // to compress instead of dividing by 2 after adding signals

// Line to interpolate frequency for aSin0.

Line <Q16n16> aInterpolate;
Line <Q16n16> bInterpolate;
Line <Q16n16> cInterpolate;
Line <Q16n16> dInterpolate;
Line <Q16n16> eInterpolate;
Line <Q16n16> fInterpolate;
Line <Q16n16> gInterpolate;
Line <Q16n16> hInterpolate;
Line <Q16n16> iInterpolate;
Line <Q16n16> jInterpolate;

// the number of audio steps the line has to take to reach the next control value
const unsigned int AUDIO_STEPS_PER_CONTROL = 64;//AUDIO_RATE / CONTROL_RATE;
const int FIVE_MINS = CONTROL_RATE*5*60;

int runtime =0;
float f1_freq;
#define F1START 898.5f
#define F1END 22.251f
#define F2START 999.f
#define F2END 165.f
#define F3START 1300.f
#define F3END 165.2f
#define F4START 2134.f
#define F4END 164.5f
#define F5START 10.f
#define F5END 165.01f

#define F6START 2290.f
#define F6END 111.1f
#define F7START 2322.f
#define F7END 82.21f
#define F8START 999.f
#define F8END 82.5f
#define F9START 1400.f
#define F9END 82.91f
#define F10START 700.f
#define F10END 165.1f

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  runtime = 0;

  //set up frequency lines
  aInterpolate.set(float_to_Q16n16(F1START),float_to_Q16n16(F1END),FIVE_MINS);
  bInterpolate.set(float_to_Q16n16(F2START),float_to_Q16n16(F2END),FIVE_MINS);
  cInterpolate.set(float_to_Q16n16(F3START),float_to_Q16n16(F3END),FIVE_MINS);
  dInterpolate.set(float_to_Q16n16(F4START),float_to_Q16n16(F4END),FIVE_MINS);
  eInterpolate.set(float_to_Q16n16(F5START),float_to_Q16n16(F5END),FIVE_MINS);
  fInterpolate.set(float_to_Q16n16(F6START),float_to_Q16n16(F6END),FIVE_MINS);
  gInterpolate.set(float_to_Q16n16(F7START),float_to_Q16n16(F7END),FIVE_MINS);
  hInterpolate.set(float_to_Q16n16(F8START),float_to_Q16n16(F8END),FIVE_MINS);
  iInterpolate.set(float_to_Q16n16(F9START),float_to_Q16n16(F9END),FIVE_MINS);
  jInterpolate.set(float_to_Q16n16(F10START),float_to_Q16n16(F10END),FIVE_MINS);

  startMozzi(CONTROL_RATE);
 
}


void updateControl(){

    if(runtime % 64 ==0){
      Serial.print("runtime \t");Serial.println(runtime); 
    }

    //if we have ended.
    if(runtime > FIVE_MINS){
      aInterpolate.set(float_to_Q16n16(F1END),float_to_Q16n16(F1END),FIVE_MINS);
      bInterpolate.set(float_to_Q16n16(F2END),float_to_Q16n16(F2END),FIVE_MINS);
      cInterpolate.set(float_to_Q16n16(F3END),float_to_Q16n16(F3END),FIVE_MINS);
      dInterpolate.set(float_to_Q16n16(F4END),float_to_Q16n16(F4END),FIVE_MINS);
      eInterpolate.set(float_to_Q16n16(F5END),float_to_Q16n16(F5END),FIVE_MINS);
      fInterpolate.set(float_to_Q16n16(F6END),float_to_Q16n16(F6END),FIVE_MINS);
      gInterpolate.set(float_to_Q16n16(F7END),float_to_Q16n16(F7END),FIVE_MINS);
      hInterpolate.set(float_to_Q16n16(F8END),float_to_Q16n16(F8END),FIVE_MINS);
      iInterpolate.set(float_to_Q16n16(F9END),float_to_Q16n16(F9END),FIVE_MINS);
      jInterpolate.set(float_to_Q16n16(F10END),float_to_Q16n16(F10END),FIVE_MINS);
      Serial.println("end line");  //this makes some nice glitching sounds after the 5minute mark
      //probs should turn on red LED here.    
    }

    aSin0.setFreq_Q16n16(aInterpolate.next());
    bSin0.setFreq_Q16n16(bInterpolate.next());
    cSin0.setFreq_Q16n16(cInterpolate.next());
    dSin0.setFreq_Q16n16(dInterpolate.next());
    eSin0.setFreq_Q16n16(eInterpolate.next());
    fSin0.setFreq_Q16n16(fInterpolate.next());
    gSin0.setFreq_Q16n16(gInterpolate.next());
    hSin0.setFreq_Q16n16(hInterpolate.next());
    iSin0.setFreq_Q16n16(iInterpolate.next());
    jSin0.setFreq_Q16n16(jInterpolate.next());
    
    runtime++;
}

int updateAudio(){
  int snd = (int)(aSin0.next()+bSin0.next()+cSin0.next() + dSin0.next() )>>2;
  int snd2 = (int)(eSin0.next() +fSin0.next() +gSin0.next()+hSin0.next() + iSin0.next() + jSin0.next())>>3;
  return aCompress.next(256u + snd + snd2);
 
 }


void loop() {
  // put your main code here, to run repeatedly:
  audioHook();
}



Code for Arduino #3 (Uses audio input)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
*  Jun27a  Reverb Code.  ReverTank.h needs to be changed to fit into the memory of the Pro Mini
*/

#include <MozziGuts.h>
#include <ReverbTank.h>
#include <tables/waveshape_compress_512_to_488_int16.h>
#include <WaveShaper.h>

WaveShaper <int> aCompress(WAVESHAPE_COMPRESS_512_TO_488_DATA);
ReverbTank reverb;

#define CONTROL_RATE 64

void setup() {
  // put your setup code here, to run once:
  startMozzi(CONTROL_RATE);
}

void updateControl(){
  return;
}

int updateAudio(){
 int asig = getAudioInput(); // range 0-1023
  asig = asig - 512; // now range is -512 to 511
  asig >>= 2; // now it's -128 to 127, within audio output range

  // use a waveshaping table to squeeze 2 summed 8 bit signals into the range -244 to 243
  int awaveshaped3 = aCompress.next(256u + asig);
  int arev = reverb.next(awaveshaped3);
  return arev;  
}

void loop() {
  // put your main code here, to run repeatedly:
  audioHook();
}



Electronics

The Arduinos use a PWM signal to output the audio.  the PWM rate used is ~32kHz, with a sample update rate of ~16kHz.
To reduce the PWM and aliasing noise, a simple RC filter was put on the outputs of the Arduinos, before they were fed into the mixer.
See the circuit drawings below.



Updated 11-July-2017
Go Home