Close

Soundboxen Examples

A project log for Fluxamasynth Modules

The Fluxamasynth is a module that makes it easy to add high quality MIDI sound to any Arduino or Raspberry Pi project.

fluxlyFluxly 10/01/2018 at 21:280 Comments

The Fluxamasynth is well suited for making musical appliances. One example is from a series of Soundboxen; this one is inspired by Brian Eno's Music for Airports tape loops. For this appliance the length of each loop is determined by one of the potentiometers. The Arduino code for Fluxamasynth is here:

// Inspired by Eno's Music for Airports #2: 
// F2 G#2 C3 C#3 D#3 F3 G#3
// Reads poteniometers on A0-A5

#include "Fluxamasynth.h"
Fluxamasynth synth;

int tones[6] = { 29, 32, 36, 37, 39, 41 };
int instruments[6] = { 55, 55, 55, 55, 55, 55 };
int tapeLength[6] = { 30, 31, 32, 33, 34, 35  };
int startingPoint[6] = { 0, 1, 2, 3, 4, 5 };
int length[6] = { 100, 110, 120, 130, 140, 150 };
int lengthCount[6] = { 0, 0, 0, 0, 0, 0 };
int tempo[6] = { 1000, 2000, 3000, 4000, 5000, 6000 };
int tempoCount[6] = { 0, 0, 0, 0, 0, 0 };
long int startTime = 0;

void setup() {
  Serial.begin(9600);
  int seed = 0;
  for (int i=0; i<6; i++) {
    seed += analogRead(i);
  }

  randomSeed(seed);
  delay(100);
  for (int i=0; i<6; i++) {
    synth.setChannelVolume(i, 255 );  
    synth.allNotesOff(i);    
    synth.setReverb(i, 5, 64, 0);
    synth.pan(5-i,127/(6*(i+1)));
  }
  changeProgram();
  startTime = 0;
}

void changeProgram() {
   for (int i=0; i<6; i++) {
      synth.programChange(0, i,random(127));
   }
}

void loop() {
  if (millis() > (startTime + 5000)) {
    changeProgram();
    startTime = millis();
    Serial.println("changeProgram");
  }
  int ledTempo = 0;
  for (int i=0; i<6; i++) {
    int val = analogRead(i);
    tempo[i] = 5100 - map(val, 0, 1023, 100, 5000); 
    tempoCount[i]++;
    if (tempoCount[i] > tempo[i]) {
      if (lengthCount[i] == 0) {
        synth.noteOn(i, tones[i], 127);
      }
      lengthCount[i]++;
      if (lengthCount[i] > length[i]) {
        synth.noteOff(i, tones[i]);
        lengthCount[i] = 0;
        tempoCount[i] = 0;
      }
    }
  }  
  delay(1);
}

 Here's the result:

Here's one more example of a musical appliance: a radio station broadcasting generative music using Orff instruments on 102.5. This uses the Adafruit FM transmitter module and a Fluxamasynth to generate the music.

And the Arduino code:

#include <Wire.h>
#include <Adafruit_Si4713.h>
#include <fluxamasynth.h>
#include <pgmchange.h></pgmchange.h></fluxamasynth.h>

#define RESETPIN 12
//#define FMSTATION 8830      // 10230 == 102.30 MHz
#define FMSTATION 10250

Adafruit_Si4713 radio = Adafruit_Si4713(RESETPIN);
Fluxamasynth synth = Fluxamasynth();

#define numInstruments 4

byte parts[4];
int measures[16];
int notes[16];
int rhythm[16];
int percussion[16];
char partName[4] = {'a','b','c','d'};
int noteName[16];
int binaryChoice[16];
int noteOn[4] = {0, 0, 0, 0};
int rhythmOn[4] = {0, 0, 0, 0};
int tempo=30;

// Limit instrument choice
int instrument[numInstruments] = {13, 13, 13, 13};

void setup() {
  randomSeed(millis()+analogRead(0));
  Serial.begin(9600);
  chooseParts();
  synth.setMasterVolume(127);
  for (int i=0; i<numInstruments; i++) {
    synth.programChange(0, i, instrument[i]);
    pan(i,127/numInstruments*i);
    //synth.setChannelVolume(i, volume[i]);
    synth.setReverb(i, 3, 127, 25);
  }
  synth.setReverb(9,5,255,100);   //Plate reverb
  
  delay(1000);
  Serial.println("Adafruit Radio - Si4713 Test");

  if (! radio.begin()) {  // begin with address 0x63 (CS high default)
    Serial.println("Couldn't find radio?");
    while (1);
  }
}

void chooseParts() {
  parts[0] = random(254)+1;
  parts[1] = random(255);
  parts[1] = parts[1] & (parts[1]^parts[0]);
  parts[2] = random(255);
  parts[2] = parts[2] & (parts[2]^(parts[0]|parts[1]));
  parts[3] = ~(parts[0]|parts[1]|parts[2]);
}

void chooseMeasures(int p) {
  measures[0+p] = random(254)+1;
  measures[1+p] = random(255);
  measures[1+p] = measures[1+p] & (measures[1+p]^measures[0+p]);
  measures[2+p] = random(255);
  measures[2+p] = measures[2+p] & (measures[2+p]^(measures[0+p]|measures[1+p]));
  measures[3+p] = ~(measures[0+p]|measures[1+p]|measures[2+p]);
}

void chooseNotes(int p) {
  int baseNote = random(40)+50;
  noteName[p] = baseNote;
  noteName[p+1]=baseNote +  (random(3)-1)*7;
  noteName[p+2]=baseNote +  (random(3)-1)*4 + random(3)-1;
  noteName[p+3]=baseNote + (random(3)-1)*random(8);
}

void chooseRhythm(int p) {
  rhythm[0+p] = random(254)+1;
  rhythm[1+p] = random(255);
  rhythm[1+p] = rhythm[1+p] & (rhythm[1+p]^rhythm[0+p]);
  rhythm[2+p] = random(255);
  rhythm[2+p] = rhythm[2+p] & (rhythm[2+p]^(rhythm[0+p]|rhythm[1+p]));
  rhythm[3+p] = ~(rhythm[0+p]|rhythm[1+p]|rhythm[2+p]);
}

void choosePercussion(int p) {
  //percussion[p] = 36;
  //percussion[p+1]=38;
  //percussion[p+2]=42;
  //percussion[p+3]=44;
  percussion[p] = random(127);
  percussion[p+1]=random(127);
  percussion[p+2]=random(127);
  percussion[p+3]=random(127);
}

void loop() {

  // New Song
  for (int i=0; i<numInstruments; i++) {
    synth.allNotesOff(i);
  }
  
  tempo = random(200)+10;

  for (int i=0; i<4; i++) {
        instrument[i] = 13;
        synth.programChange(0, i, instrument[i]);
  }

  int numSections = random(20)+60;
  for (int m=0; m<4; m++) {
    choosePercussion(m);
  }
 
  for (int sections=0; sections<numSections; sections++) {
    
    chooseParts();

    for (int m=0; m<4; m++) {
       chooseMeasures(m);
       chooseNotes(m);
       chooseRhythm(m);
    }
    
    for (int i=0; i<16; i++) {
      if (random(100)>50) {
        binaryChoice[i] = 1;
      } else {
        binaryChoice[i] = 0;
      }
    }
    tempo = tempo-random(tempo/160);

// TODO: Add four time channels: triplet, quad, 
// quintuplet, septuplet

    while(random(100)<10) {
      for (int i=0; i<8; i++) {
      Serial.println();
      for (int part =0; part<4; part++) {
        if ((parts[part]>>i) & 0x01) {
          Serial.print(partName[part]);
          for (int beat =0; beat<8; beat++) {
            delay(tempo);
            
            for (int voice=0; voice<4; voice++) {
              if (((measures[part+voice]>>beat) & 0x01)==binaryChoice[part+voice]) {
                if (noteOn[voice]!=noteName[part+voice]) {
                  if (noteOn[voice]==0) {
                    Serial.print(voice);
                    synth.noteOn(voice, noteName[part+voice], 127);
                    noteOn[voice] = noteName[part+voice];
                  } else {
                    synth.noteOff(voice, noteOn[voice]);
                    synth.noteOn(voice, noteName[part+voice], 127);
                    //Serial.print("PrevOff");
                    //Serial.print("On");
                    noteOn[voice] = noteName[part+voice];
                  }
                } else {
                    //Serial.print("Hold");
                }

              } else {
                if (noteOn[voice]) {
                  synth.noteOff(voice, noteOn[voice]);
                  noteOn[voice]=0;
                }
              }
              if (((rhythm[part+voice]>>beat) & 0x01)==binaryChoice[part+voice]) {
                if (!rhythmOn[voice]) {
                  rhythmOn[voice]=1;
                  synth.noteOn(9, percussion[voice], 100) ;
                  synth.noteOff(9, percussion[voice]) ;
                } 
              } else {
                rhythmOn[voice]=0;
              }
            }
          }
        }
      }
    }
  }
}
  
   delay(2000);

}

void pan(int channel, int value) {
  // TODO: Add this to library (done)
  byte command[3] = {
    (0xb0 | (channel & 0x0f)), 0x0A, (value)   };
  synth.fluxWrite(command, 3);
}

Discussions