top of page
Search
  • Writer's picture1/4" Jack Of All Trades

Physical Computing Christmas 2 - Mozzi + FastLED and Glass Cutting

Updated: Jan 3, 2021


In this episode of physical computing I carried on tweaking the Mozzi patch I have been working on and included a WS811 RGB LED strip (using the FastLED library). The goal of my project is to create a decorative synth and to this end I experimented using conditional logic dependent on the position of the various knobs to switch between LED patterns that I borrowed from the FastLED examples for the WS811 LED strips.


The code is as follows:

#include <MozziGuts.h>
#include <Oscil.h> // oscillator 
#include <tables/cos2048_int8.h> // table for Oscils to play
#include <Smooth.h>
#include <AutoMap.h> // maps unpredictable inputs to a range
#include <FastLED.h>
#include <EventDelay.h>

FASTLED_USING_NAMESPACE

#if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000)
#warning "Requires FastLED 3.1 or later; check github for latest code."
#endif


#define DATA_PIN    3
//#define CLK_PIN   4
#define LED_TYPE    WS2811
#define COLOR_ORDER GRB
#define NUM_LEDS    300
CRGB leds[NUM_LEDS];

#define BRIGHTNESS          96
#define FRAMES_PER_SECOND  120
 
// int freqVal;
 
// desired carrier frequency max and min, for AutoMap
const int MIN_CARRIER_FREQ = 22;
const int MAX_CARRIER_FREQ = 1000;

const int MIN = 1;
const int MAX = 20;

const float MIN_2 = 0.1;
const float MAX_2 = 15.0;


const float MIN_3 = 0.1;
const float MAX_3 = 10.0;

// desired intensity max and min, for AutoMap, note they're inverted for reverse dynamics
const int MIN_INTENSITY = 700;
const int MAX_INTENSITY = 10;

// desired mod speed max and min, for AutoMap, note they're inverted for reverse dynamics
const int MIN_MOD_SPEED = 10000;
const int MAX_MOD_SPEED = 1;

AutoMap kMapCarrierFreq(0,1023,MIN_CARRIER_FREQ,MAX_CARRIER_FREQ);
AutoMap kMapIntensity(0,1023,MIN_INTENSITY,MAX_INTENSITY);
AutoMap kMapModSpeed(0,1023,MIN_MOD_SPEED,MAX_MOD_SPEED);
AutoMap mapThis(0,1023,MIN,MAX);
AutoMap mapThisToo(0,1023,MIN_2,MAX_2);
AutoMap mapThisSmooth(0,1023,MIN_3,MAX_3);

const int KNOB_PIN = 0; // set the input for the knob to analog pin 0
const int LDR1_PIN=1; // set the analog input for fm_intensity to pin 1
const int LDR2_PIN=2; // set the analog input for mod rate to pin 2
const int LDR3_PIN=3;
const int LDR4_PIN=4;
const int LDR5_PIN=5;


Oscil<COS2048_NUM_CELLS, AUDIO_RATE> aCarrier(COS2048_DATA);
Oscil<COS2048_NUM_CELLS, AUDIO_RATE> aModulator(COS2048_DATA);
Oscil<COS2048_NUM_CELLS, CONTROL_RATE> kIntensityMod(COS2048_DATA);

int mod_ratio = 5; // brightness (harmonics)
long fm_intensity; // carries control info from updateControl to updateAudio

// smoothing for intensity to remove clicks on transitions
float smoothness = 0.95f;
Smooth <long> aSmoothIntensity(smoothness);

EventDelay EvDel;

void setup(){
  //Cap Sense
  cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF);
  //Fast LED
  delay(3000); // 3 second delay for recovery
  FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(BRIGHTNESS);
  //Mozzi
  Serial.begin(115200); 
  pinMode(7, OUTPUT); //AUDIO OUTPUT
  startMozzi(); 
}

uint8_t gHue = 0;

void updateControl(){
  
//  freqVal = map(LDR3_PIN, 0, 1023, 1, 100);
  
   float freqVal = mozziAnalogRead(LDR4_PIN); // value is 0-1023
   float FRQ = (float)mapThisToo(freqVal);
   
   int knob2 = mozziAnalogRead(LDR3_PIN); // value is 0-1023
   int knob2Val = mapThis(knob2);
  
  // read the knob
  int knob_value = mozziAnalogRead(KNOB_PIN); // value is 0-1023

  float LDR5_value = mozziAnalogRead(LDR5_PIN); // value is 0-1023
  float knob5Val = (float)mapThisToo(LDR5_value);
 
  // map the knob to carrier frequency
  int carrier_freq = kMapCarrierFreq(knob_value);
  
  //calculate the modulation frequency to stay in ratio
  int mod_freq = carrier_freq * mod_ratio * FRQ;
  
  // set the FM oscillator frequencies
  aCarrier.setFreq(carrier_freq); 
  aModulator.setFreq(mod_freq * knob5Val);
  
  // read the pot on the width Analog input pin
  int LDR1_value= mozziAnalogRead(LDR1_PIN); // value is 0-1023
  // print the value to the Serial monitor for debugging
  Serial.print("LDR1 = "); 
  Serial.print(LDR1_value);
  Serial.print("\t"); // prints a tab

  int LDR1_calibrated = kMapIntensity(LDR1_value);
  Serial.print("LDR1_calibrated = ");
  Serial.print(LDR1_calibrated);
  Serial.print("\t"); // prints a tab
  
 // calculate the fm_intensity
  fm_intensity = ((long)LDR1_calibrated * knob2Val * (kIntensityMod.next()+128))>>8; // shift back to range after 8 bit multiply
  Serial.print("fm_intensity = ");
  Serial.print(fm_intensity);
  Serial.print("\t"); // prints a tab
  
  
  int LDR2_value= mozziAnalogRead(LDR2_PIN); // value is 0-1023
  Serial.print("LDR2 = "); 
  Serial.print(LDR2_value);
  Serial.print("\t"); // prints a tab
  
  // use a float here for low frequencies
  float mod_speed = (float)kMapModSpeed(LDR2_value)/FRQ;
  Serial.print("   mod_speed = ");
  Serial.print(mod_speed);
  kIntensityMod.setFreq(mod_speed);

  Serial.print("LDR4 = "); 
  Serial.print(freqVal);
  Serial.print("\t"); // prints a tab

  FastLED.show();  
  EvDel.set(mod_speed/FRAMES_PER_SECOND);
  
  //Serial.println(); // finally, print a carraige return for the next line of debugging info
   if (knob_value > 500){
    confetti(mod_speed);
  }
  else {
   sinelon(mod_speed);
  }
 gHue++;
  
}

int updateAudio(){
  long modulation = aSmoothIntensity.next(fm_intensity) * aModulator.next();
  return aCarrier.phMod(modulation);
}

void loop(){
  audioHook();
}

void sinelon(float speed)
{
  // a colored dot sweeping back and forth, with fading trails
  fadeToBlackBy( leds, NUM_LEDS, speed);
  int pos = beatsin16( 13, 0, NUM_LEDS-1 );
  leds[pos] += CHSV( gHue, 255, 192);
}

void confetti(float speed) 
{
  // random colored speckles that blink in and fade smoothly
  fadeToBlackBy( leds, NUM_LEDS, speed);
  int pos = random16(NUM_LEDS);
  leds[pos] += CHSV( gHue + random8(64), 200, 255);
}

The Mozzi patch itself also still needs some more work refining the sound a bit, currently it is a bit too chaotic. My plan going forward is to revert back to an earlier version that is a bit closer to the Mozzi FM synth example and work on adding audio effects to that, such as a flanger/comb filter to hopefully get slightly more musical results.


I also spent some time testing the Arduino capacitive library, although not yet with Mozzi.

Next step is to begin building the enclosure and testing capacitive paint as a means of control of the synth.


Glass Cutting


Since the inception of the project I have intended that it should use as many recycled materials in its construction as possible. Part of the decorative nature of the synth is to be an ambient light, so it needs some amount of transparency so that the lights can be visible.


I used a glass scoring device to carve a small line around the body of the bottle and then alternated cold and boiling water until it cracked along the line. At least, this is what was supposed to happen. My first few attempts were quite wonky, but fortunately there were a quite a few wine bottles lying around following Christmas, so I had plenty of chances for practice. Although none of my attempts were perfect I did end up getting a nearly clean cut on one or two bottles.

Scoring the glass (this one was too thick)



The first of a few messy cuts

10 views0 comments
bottom of page