Hackster is hosting Hackster Holidays, Ep. 7: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 7 on Friday!
Daniel Sinderson
Published © MIT

PhaseMod Drone Synth (w/ Arduino Nano & Mozzi)

A small noise/drone synth with percussion mode. Made using the Mozzi library and two Arduino Nanos.

IntermediateShowcase (no instructions)10,349
PhaseMod Drone Synth (w/ Arduino Nano & Mozzi)

Things used in this project

Story

Read more

Schematics

Schematic

KiCad file

Schematic picture

PNG of the schematic

Code

ThankYou Synth

Arduino
Not the cleanest code here. Project was thrown together pretty quickly.
/*
Synth for a friend using the amazing Mozzi library by Tim Barrass
 */

#include <MozziGuts.h>
#include <Oscil.h>
#include <Smooth.h>
#include <AutoMap.h>
#include <ADSR.h>

#include <tables/sin256_int8.h>
#include <tables/halfsin256_uint8.h>
#include <tables/waveshape1_softclip_int8.h>
#include <tables/saw256_int8.h>



// VARIABLES
AutoMap kMapCarrierFreq(0,1023,20,440);
AutoMap kMapIntensity(0,1023,700,1);
AutoMap kMapModSpeed(0,1023,10000,0);
AutoMap kMapEnvelopeTimes(0, 1023, 20, 500);

Oscil <256, AUDIO_RATE> carrier;
Oscil <256, AUDIO_RATE> modulator;
Oscil <256, CONTROL_RATE> modDepth;

ADSR <AUDIO_RATE, AUDIO_RATE> envelope;

int attack = 20;
int decay = 20;
bool mode = 0;
bool noteTrigger = 0;
bool noteTrigger2 = 0;

int freqs[3];
byte wfs[3];

int mod_ratio = 1; //frequency of the modulator as an integer multiple of the carrier
long fm_intensity; // carries control info from updateControl to updateAudio

float smoothness = 0.95f;
Smooth <long> aSmoothIntensity(smoothness);


// FUNCTIONS
void setWavetables() {n
  if (wfs[0]==0) {carrier.setTable(SIN256_DATA);}
  else if (wfs[0]==1) {carrier.setTable(HALFSIN256_DATA);}
  else if (wfs[0]==2) {carrier.setTable(SAW256_DATA);}
  else if (wfs[0]==3) {carrier.setTable(WAVESHAPE1_SOFTCLIP_DATA);}

  if (wfs[1]==0) {modulator.setTable(SIN256_DATA);}
  else if (wfs[1]==1) {modulator.setTable(HALFSIN256_DATA);}
  else if (wfs[1]==2) {modulator.setTable(SAW256_DATA);}
  else if (wfs[1]==3) {modulator.setTable(WAVESHAPE1_SOFTCLIP_DATA);}

  if (wfs[2]==0) {modDepth.setTable(SIN256_DATA);}
  else if (wfs[2]==1) {modDepth.setTable(HALFSIN256_DATA);}
  else if (wfs[2]==2) {modDepth.setTable(SAW256_DATA);}
  else if (wfs[2]==3) {modDepth.setTable(WAVESHAPE1_SOFTCLIP_DATA);}
}

void readPins() {
  freqs[0] = mozziAnalogRead(A0);
  freqs[1] = mozziAnalogRead(A1);
  freqs[2] = mozziAnalogRead(A2);
  
  wfs[0] = mozziAnalogRead(A3) >> 8;
  wfs[1] = mozziAnalogRead(A4) >> 8;
  wfs[2] = mozziAnalogRead(A5) >> 8;

  mod_ratio = (mozziAnalogRead(A6) >> 7) + 1;
  decay = mozziAnalogRead(A7);

  mode = digitalRead(4);
  noteTrigger = digitalRead(2);
  noteTrigger2 = digitalRead(3);
}

void setFrequencies() {
    int carrier_freq = kMapCarrierFreq(freqs[0]);
    int mod_freq = carrier_freq * mod_ratio;

    int intensity_calibrated = kMapIntensity(freqs[2]);
    fm_intensity = ((long)intensity_calibrated * (modDepth.next()+128))>>8;

    float mod_speed = (float)kMapModSpeed(freqs[1])/1000;

    carrier.setFreq(carrier_freq);
    modulator.setFreq(mod_freq);
    modDepth.setFreq(mod_speed);    
}

void setAD() {
  envelope.setReleaseTime(kMapEnvelopeTimes(decay));
}



// ################### THE GOODS! #####################

void setup() {
  pinMode(4, INPUT);
  pinMode(3, INPUT);
  pinMode(2, INPUT_PULLUP);
  startMozzi();
  envelope.setLevels(255, 250, 250, 0);
  envelope.setTimes(20, 20, 5000, 20);
}

void updateControl() {
  readPins();
  setWavetables();
  setFrequencies();
  setAD();

  if (noteTrigger == 0 or noteTrigger2 == 1) { envelope.noteOn(); }
  else if (noteTrigger == 1 and noteTrigger2 == 0) { envelope.noteOff(); }
}

int updateAudio() {
  int audio;

  if (mode == 0) {
    long mod = aSmoothIntensity.next(fm_intensity) * modulator.next();
    audio = carrier.phMod(mod);
  }
  else {
    envelope.update();
    long mod = aSmoothIntensity.next(fm_intensity) * modulator.next();
    audio = ((carrier.phMod(mod) * envelope.next()) >> 8);
  }
  return audio << 6; // 14-bit number for HI-FI mode
}

void loop() {
  audioHook();
}

Credits

Daniel Sinderson
2 projects • 23 followers
I'm a writer and data specialist with a weakness for loud noises and harsh digital synthesizers.

Comments