Search
  • 1/4" Jack Of All Trades

Physical Computing Christmas 1 - Return to Digital Synthesis

Updated: Jan 7

Back to Digital Synthesis


Demo Video of Mozzi FM Synth


My process with electronics has developed into a fairly organic process with lots of improvisation, meaning that creating circuit diagrams can become very confusing very quickly, and I have totally written off the idea of getting a PCB printed as I imagine I will be tweaking my circuitry up until the 11th hour. I have instead order a stack of protoboards with a similar layout to a breadboard so that copying circuits over should be fairly trivial.


As a result I started moving back toward the Mozzi library for my audio synthesis. I started building this project to then further tweak. I began by adding an additional potentiometer for more controls (there are no LDRs in use only pots, just the name used, to be cleaned up later).



Here is the code for the tweaked synth:


#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 <CapacitiveSensor.h>// 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; // they are all knobs in my physical circuit, to be renamed at a later date.

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;
float smoothness = 0.95f;
Smooth <long> aSmoothIntensity(smoothness);void setup(){
  Serial.begin(115200); // set up the Serial output so we can look at the light level
   pinMode(7, OUTPUT);  startMozzi(); // :))
}

void updateControl()
{   
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 light dependent resistor 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"); 
  fm_intensity = ((long)LDR1_calibrated * knob2Val * (kIntensityMod.next()+128))>>8;
  Serial.print("fm_intensity = ");
  Serial.print(fm_intensity);
  Serial.print("\t"); 
  
  int LDR2_value= mozziAnalogRead(LDR2_PIN); // value is 0-1023
  Serial.print("LDR2 = ");
  Serial.print(LDR2_value);
  Serial.print("\t");
  
  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  Serial.println();
   if (knob_value > 500){
    digitalWrite(7, HIGH);
  }
  else
  digitalWrite(7, LOW);
  
}int updateAudio(){
  long modulation = aSmoothIntensity.next(fm_intensity) * aModulator.next();
  return aCarrier.phMod(modulation);
  
}void loop(){
  audioHook();
}

Next Steps


I then went on to try and add the MPR121 capacitive touch sensor library. However, this is where I ran into some pretty extreme difficulties that are currently far beyond my Arduino knowledge. I kept receiving the following error message:


libraries/Wire/utility/twi.c.o (symbol from plugin): In function `twi_init':
(.text+0x0): multiple definition of `__vector_36'
libraries/Mozzi-master/twi_nonblock.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
exit status 1

After a little digging I figured out that the error was due to a conflict between the Mozzi library and the MPR121 library. Both require uninterrupted access to I2C communication in order to function correctly. In my search for an answer I found that there is an included

Mozzi example that uses I2C communication without blocking audio synthesis for an ADXL345 accelerometer, “demonstrating use of twi_nonblock functions to replace processor-blocking wire methods”, but at present I am at a total loss on how to understand this example or how to alter it for the MPR121, or if it is even possible!

I found another example that had altered the same example to work with an MMA7660 accelerometer, which has given me some hope that this may indeed work with enough head scratching.


However, all is not lost for my experimentations with capacitive touch as a means of human-music-interaction, the Arduino capacitive touch library does not require the use of <Wire.h> which seemed to be the source of the previous conflict, meaning that hopefully I can use some amount (albeit a smaller number than if I use the MPR121) of touch sensors in my final design. Capacitive touch sensors done in this manner required two digital pins each, which obviously reduces the total number I can use (although experimentations with shift registers may therefore be in order). At present I am waiting for the arrival of some larger value resistors and some LED strips so that I can begin to experiment with the visual part of the project.


Another alternative is to abandon Mozzi altogether and move back towards analogue synthesis, which the MPR121 capacitive touch sensor being allowed exclusive reign over the Arduino. However, the sonic results I have got from Mozzi have been very interesting and I find the use of code to create sound allows for much more controlled experimentation, than the temperamental analogue circuits that I have been playing around with. Next steps with Mozzi include adding some delay and filters, and playing around with custom wavetables.



6 views0 comments