Nano Audio (Auduino Synth) Project Schematic Check

Hello, I'm using the Nano for a project that called "Auduino", which is a simple granular synthesis synth, with MIDI input.
The Auduino Project

Using easyEDA I've got a schematic and I would greatly appreciate an extra pair of eyes in checking this.

Sincere thanks,
TonyAme

I’m not sure how this is supposed to work but you look as though you have a analog input ( midi ) going to a digital input on the nano ? ( or is that an output from the nano ?)

On that midi input you have a poliarised capacitor which is wrong way around and/or unsuitable . Combined with 50k pot , the time constant is very long , too long for audio ?

Really you ought to breadboard small sections of this to be confident it works .

Be careful that when switched off you don’t feed audio input which could back power the nano and damage it .

I assume midi in is digital control.

In the audio output c1 should be from d3 to the top of the pot. What's c2 supposed to do?

Why do you have a separate 5v regulator to feed an opto coupler, 5 pots and a LED when there's already a 5v regulator in the Nano?

What is q1 there for?

Good question.
And it gets worse.
Powering the pots from a different supply than the 5volt pin of the Nano is a recipe for instability.
I don't see the need for that 7805 at all. Everything 5volt seems to be low power.
7-9volt on V-in would be fine, 12volt is in the danger zone for a Nano.
A 5volt cellphone charger connected to the USB socket should be fine too.
Leo..

It is a restoration filter.

@tonyame without the software it is hard to see what is supposed to happen.

Well it might be, except that if it is then (a) using Arduino PWM to reconstruct an audio waveform seems a bit limiting, and (b) the cutoff frequency will depend on the volume level. So what is it for? As you say we can't tell without the software.

The PWM frequency can be set at many different frequencies depending on how you set the timer pre scaler divide ratio. In an audio application I tend to set the PWM frequency to about 80 to 100 KHz, and then that value makes more sense.

Yes there needs to be a series resistor of about 1K5 after C1 and then C2 moved to the other side of this resistor. In other words directly across the audio output.

Hello, Sorry, I should have explained this more. Q1 is a P-Channel Mosfet for power polarity protection, it's something I just started using and came from this post in allaboutcircuits.com forum by Jon Chandler: Using P-Channel Mosfet for reverse polarity protection.

Also, I'm using Vin to power the Nano with 7-9V. The regulated 5V taken from the output of the 7805 will power the peripherals which I will be adding to this main board, such as I2c LCD, MPR121 cap touch board, and maybe an analog multiplexer.

I want to make sure I have enough amps for all of that stuff. (Does anyone else have power problems when adding stuff to your circuit?) This seems to remedy that. I'll find the original post where I learned about this.

The use of the P-channel mosfet for polarity protection, and powering the nano separately worked great for me in a previous project.

C2 is part of the audio output filter. (Hammy, I think you're referring to the polarized cap on the audio output circuit? Where it says Audio Out, there should be a 1/4" output phone jack there. I don't see a polarized cap on the MIDI input circuit.)

I'm not sure, but maybe the output volume pot R6 is causing confusion. Maybe I put it in the wrong place. Where it is now I believe it would work as part of the filtering circuit, not volume.

I'll try to address these questions in my next post (and post the code). Thanks for the help.

TonyAm

Get a nice, solid 5V power supply (not a phone charger) and feed everything that needs 5V from it. No design of nada.

Hello,

The forum post which discussed using the power scheme in my schematic originates here: Check out what eetech00 said at post #12

This code comes from Nuts and Volts website but originated from tinker.it as sighted below.

The only changes I made so far were to omit the DIP switch for digital pins D9-D12, I omitted pots at A4 and A5 so that I could use I2C SDA and SCL. *And I changed the way the Nano and board peripherals are powered.

// ************************************************************************
// AUDUINO - MIDI Upgrade v1.1
// For Arduino NANO
//
// MIDI programming by Notes and Volts http://www.notesandvolts.com
//
// Tutorial - http://www.notesandvolts.com/2015/05/auduino-synth-midi.html
// 
// ** Requires Arduino MIDI Library v4.2 or later **
//
// Based on the Auduino Synthesizer v5 by Peter Knight http://tinker.it
// ************************************************************************
// Version 1.0 - Initial release
// Version 1.1 - Fixed bug that caused note to hang with some DAWs
// ************************************************************************

#include <avr/io.h>
#include <avr/interrupt.h>
#include <MIDI.h> // Requires Arduino MIDI Library v4.2 or later

// *** MIDI Parameters ***********************************************************
#define BENDRANGE 12 // Change to set Number of Semitones for Pitch Bend (1 to 24)
// *******************************************************************************
// If the DIP Switch option is installed - set dipSwitchInstalled to "true"
const bool dipSwitchInstalled = false;
// DIP Switch Setting = Channel (1=ON, 0=OFF)
// 0000 = 1   0001 = 2   0010 = 3   0011 = 4
// 0100 = 5   0101 = 6   0110 = 7   0111 = 8
// 1000 = 9   1001 = 10  1010 = 11  1011 = 12
// 1100 = 13  1101 = 14  1110 = 15  1111 = 16
//
// If DIP Switch is NOT installed - change dipSwitchInstalled to "false"
// If dipSwitchInstalled is set to false, the MIDI channel will be set
// to the value of MIDICHANNEL
#define MIDICHANNEL 1 // Can be a value from 1 to 16
// *******************************************************************************

MIDI_CREATE_DEFAULT_INSTANCE();

uint16_t syncPhaseAcc;
uint16_t syncPhaseInc;
uint16_t grainPhaseAcc;
uint16_t grainPhaseInc;
uint16_t grainAmp;
uint8_t grainDecay;
uint16_t grain2PhaseAcc;
uint16_t grain2PhaseInc;
uint16_t grain2Amp;
uint8_t grain2Decay;

// DIP Switch Pins
#define DIP_SW1 9
#define DIP_SW2 10
#define DIP_SW3 11
#define DIP_SW4 12

// Map Analogue channels
#define SYNC_CONTROL         (4)
#define GRAIN_FREQ_CONTROL   (0)
#define GRAIN_DECAY_CONTROL  (2)
#define GRAIN2_FREQ_CONTROL  (3)
#define GRAIN2_DECAY_CONTROL (1)

#define BUFFER 8 //Size of keyboard buffer

#if defined(__AVR_ATmega8__)
//
// On old ATmega8 boards.
//    Output is on pin 11
//
#define LED_PIN       13
#define LED_PORT      PORTB
#define LED_BIT       5
#define PWM_PIN       11
#define PWM_VALUE     OCR2
#define PWM_INTERRUPT TIMER2_OVF_vect
#elif defined(__AVR_ATmega1280__)
//
// On the Arduino Mega
//    Output is on pin 3
//
#define LED_PIN       13
#define LED_PORT      PORTB
#define LED_BIT       7
#define PWM_PIN       3
#define PWM_VALUE     OCR3C
#define PWM_INTERRUPT TIMER3_OVF_vect
#else
//
// For modern ATmega168 and ATmega328 boards
//    Output is on pin 3
//
#define PWM_PIN       3
#define PWM_VALUE     OCR2B
#define LED_PIN       13
#define LED_PORT      PORTB
#define LED_BIT       5
#define PWM_INTERRUPT TIMER2_OVF_vect
#endif

// Smooth logarithmic mapping
//
uint16_t antilogTable[] = {
  64830, 64132, 63441, 62757, 62081, 61413, 60751, 60097, 59449, 58809, 58176, 57549, 56929, 56316, 55709, 55109,
  54515, 53928, 53347, 52773, 52204, 51642, 51085, 50535, 49991, 49452, 48920, 48393, 47871, 47356, 46846, 46341,
  45842, 45348, 44859, 44376, 43898, 43425, 42958, 42495, 42037, 41584, 41136, 40693, 40255, 39821, 39392, 38968,
  38548, 38133, 37722, 37316, 36914, 36516, 36123, 35734, 35349, 34968, 34591, 34219, 33850, 33486, 33125, 32768
};
uint16_t mapPhaseInc(uint16_t input) {
  return (antilogTable[input & 0x3f]) >> (input >> 6);
}

// Stepped chromatic mapping
//
uint16_t midiTable[] = {
  0, 18, 19, 20, 22, 23, 24, 26, 27, 29, 31, 32, 34, 36, 38, 41, 43, 46, 48, 51, 54, 58, 61, 65, 69, 73,
  77, 82, 86, 92, 97, 103, 109, 115, 122, 129, 137, 145, 154, 163, 173, 183, 194, 206, 218, 231,
  244, 259, 274, 291, 308, 326, 346, 366, 388, 411, 435, 461, 489, 518, 549, 581, 616, 652, 691,
  732, 776, 822, 871, 923, 978, 1036, 1097, 1163, 1232, 1305, 1383, 1465, 1552, 1644, 1742,
  1845, 1955, 2071, 2195, 2325, 2463, 2610, 2765, 2930, 3104, 3288, 3484, 3691, 3910, 4143,
  4389, 4650, 4927, 5220, 5530, 5859, 6207, 6577, 6968, 7382, 7821, 8286, 8779, 9301, 9854,
  10440, 11060, 11718, 12415, 13153, 13935, 14764, 15642, 16572, 17557, 18601, 19708, 20879,
  22121, 23436, 24830, 26306
};
uint16_t mapMidi(uint16_t input) {
  return (midiTable[input]);
}

// Stepped Pentatonic mapping
//
uint16_t pentatonicTable[54] = {
  0, 19, 22, 26, 29, 32, 38, 43, 51, 58, 65, 77, 86, 103, 115, 129, 154, 173, 206, 231, 259, 308, 346,
  411, 461, 518, 616, 691, 822, 923, 1036, 1232, 1383, 1644, 1845, 2071, 2463, 2765, 3288,
  3691, 4143, 4927, 5530, 6577, 7382, 8286, 9854, 11060, 13153, 14764, 16572, 19708, 22121, 26306
};

uint16_t mapPentatonic(uint16_t input) {
  uint8_t value = (1023 - input) / (1024 / 53);
  return (pentatonicTable[value]);
}

//Global Varibles used by MIDI Upgrade
byte note = 0;
byte buff[BUFFER];
byte buffersize = 0;
float bendfactor = ((BENDRANGE * 100.0) / 8190.0);
float cents = 0;
bool pot = false;
bool noteOn = false;
int oldpot = 0;
int transpose = 0;

void audioOn() {
#if defined(__AVR_ATmega8__)
  // ATmega8 has different registers
  TCCR2 = _BV(WGM20) | _BV(COM21) | _BV(CS20);
  TIMSK = _BV(TOIE2);
#elif defined(__AVR_ATmega1280__)
  TCCR3A = _BV(COM3C1) | _BV(WGM30);
  TCCR3B = _BV(CS30);
  TIMSK3 = _BV(TOIE3);
#else
  // Set up PWM to 31.25kHz, phase accurate
  TCCR2A = _BV(COM2B1) | _BV(WGM20);
  TCCR2B = _BV(CS20);
  TIMSK2 = _BV(TOIE2);
#endif
}

void setup() {
  if (dipSwitchInstalled) {
    pinMode(DIP_SW1, INPUT_PULLUP);
    pinMode(DIP_SW2, INPUT_PULLUP);
    pinMode(DIP_SW3, INPUT_PULLUP);
    pinMode(DIP_SW4, INPUT_PULLUP);
  }
  pinMode(PWM_PIN, OUTPUT);
  audioOn();
  pinMode(LED_PIN, OUTPUT);
  oldpot = analogRead(SYNC_CONTROL);
  if (dipSwitchInstalled) {
    MIDI.begin(DipSwitch());
  }
  else {
    MIDI.begin(MIDICHANNEL);
  }
  MIDI.setHandleNoteOn(NoteOnMidi);
  MIDI.setHandleNoteOff(NoteOffMidi);
  MIDI.setHandlePitchBend(Pitchbend);
}

void loop() { // *** MAIN LOOP ***

  MIDI.read();

  if (abs(analogRead(SYNC_CONTROL) - oldpot) > 5) pot = true;// Check if SYNC Pot has been touched

  // If Sync pot has been touched - Play pentatonic major scale with Root Note set by note on keyboard
  if (pot == true && noteOn == true) {
    syncPhaseInc = (mapPentatonic(analogRead(SYNC_CONTROL)) * pow(2, ((cents + transpose) / 1200)) );
    oldpot = analogRead(SYNC_CONTROL);
  }
  // If Sync pot has not been touched - Play the note sent by keyboard
  else {
    syncPhaseInc = mapMidi(note) * pow(2, (cents / 1200));
  }

  grainPhaseInc  = mapPhaseInc(analogRead(GRAIN_FREQ_CONTROL)) / 2;
  grainDecay     = analogRead(GRAIN_DECAY_CONTROL) / 8;
  grain2PhaseInc = mapPhaseInc(analogRead(GRAIN2_FREQ_CONTROL)) / 2;
  grain2Decay    = analogRead(GRAIN2_DECAY_CONTROL) / 4;
}

SIGNAL(PWM_INTERRUPT)
{
  uint8_t value;
  uint16_t output;

  syncPhaseAcc += syncPhaseInc;
  if (syncPhaseAcc < syncPhaseInc) {
    // Time to start the next grain
    grainPhaseAcc = 0;
    grainAmp = 0x7fff;
    grain2PhaseAcc = 0;
    grain2Amp = 0x7fff;
    LED_PORT ^= 1 << LED_BIT; // Faster than using digitalWrite
  }

  // Increment the phase of the grain oscillators
  grainPhaseAcc += grainPhaseInc;
  grain2PhaseAcc += grain2PhaseInc;

  // Convert phase into a triangle wave
  value = (grainPhaseAcc >> 7) & 0xff;
  if (grainPhaseAcc & 0x8000) value = ~value;
  // Multiply by current grain amplitude to get sample
  output = value * (grainAmp >> 8);

  // Repeat for second grain
  value = (grain2PhaseAcc >> 7) & 0xff;
  if (grain2PhaseAcc & 0x8000) value = ~value;
  output += value * (grain2Amp >> 8);

  // Make the grain amplitudes decay by a factor every sample (exponential decay)
  grainAmp -= (grainAmp >> 8) * grainDecay;
  grain2Amp -= (grain2Amp >> 8) * grain2Decay;

  // Scale output to the available range, clipping if necessary
  output >>= 9;
  if (output > 255) output = 255;

  // Output to PWM (this is faster than using analogWrite)
  PWM_VALUE = output;
}

// NoteOnMidi function is called when a Note On event is detected
// Put note in key buffer and set note variable
void NoteOnMidi(byte channel, byte pitch, byte velocity) {
  if (buffersize < BUFFER) {
    note = pitch;
    buff[buffersize] = pitch;
    buffersize++;
  }
  noteOn = true;
  // Set root note of Pentatonic scale
  int offset = pitch % 12;
  if (offset < 7) transpose = (5 + offset) * 100;
  else if (offset >= 7) transpose = (offset - 7) * 100;
}

// NoteOffMidi function is called when a Note Off event is detected
// If there are other notes in the key buffer (more than one key held)
// re-trigger old note. If key buffer is empty - set note to zero (off).
void NoteOffMidi(byte channel, byte pitch, byte velocity) {
  if (buffersize > 1) {
    for (int ctr = 0; ctr < buffersize; ctr++) {
      if (buff[ctr] == pitch) {

        ShiftLeft(ctr + 1);
        break;
      }
    }
    note = buff[buffersize - 1];
    int offset = note % 12;
    if (offset < 7) transpose = (5 + offset) * 100;
    else if (offset >= 7) transpose = (offset - 7) * 100;
  }
  else {
    note = 0;
    noteOn = false;
    buff[buffersize - 1] = 0;
    buffersize = 0;
  }
  pot = false;
}

// ShiftLeft closes gap in key buffer when note is removed.
void ShiftLeft(int index) {
  int ctr = (index - 1);
  for (ctr; ctr < buffersize - 1; ctr++) {
    buff[ctr] = buff[ctr + 1];
  }
  buff[ctr + 1] = 0;
  buffersize--;
}

// Pitchbend function is called when Pitchbend data is received.
// This function coverts the Pitchbend number into cents (100 cents = 1 semitone)
// In the main loop, the frequency of the note plus the pitchbend is calculated
// using this formula: Final Frequency = note * 2^(cents/1200)
void Pitchbend (byte channel, int bend) {
  cents = bend * bendfactor;
}

byte DipSwitch() {
  byte value = 0;
  if (digitalRead(DIP_SW4) == LOW)
    value += 1;
  if (digitalRead(DIP_SW3) == LOW)
    value += 2;
  if (digitalRead(DIP_SW2) == LOW)
    value += 4;
  if (digitalRead(DIP_SW1) == LOW)
    value += 8;
  return (value + 1);
}

My updated schematic. Changed the audio output volume pot.

Here is the original schematic from Nuts and Volts, *using the Arduino Nano V. 2.x.

*I am using Nano V.3.x The pins are different.

Good idea, except that a 5volt USB supply is a nice 5volt supply.
"Phone charger" is a misnomer, because the charge circuitry is inside the phone.

Can't see the images on that site without them forcing me to sign in (I won't).
I guess they didn't understand that if you connect a ratiometric sensor (pot) to a ratiometric A/D (Nano) then you should power the pot and MCU from the same point. Doesn't matter if it's internal or external, as long as both are powered from the same 5volt point. Otherwise any (fluctuating) difference between the two 5volt supplies will show up in the A/D values of the pots. It might not be much, but it can be avoided.

If you insist on using that external 5volt supply (7805), then just connect it's 5volt output to the 5volt pin of the Nano, and forget about V-in.
I don't see the point with a 7-9volt supply, because you didn't mention any high-current devices in your post, except for maybe the LCD backlight.
Leo..

Here is an edited schem of my previous project where I first used this power input scheme.

I was using the Metro Mini from Adafruit.

I didn't know either (about needing to power the pots from same source as the MCU). But for some reason it works beautifully, whereas in the past I have had problems with power when using the MCU's 5v supply and adding other things to the board; such as LCD, Mux, etc.

For those interested, check out this guys post on using the P-channel MOSFET for reverse polarity power protection:
Use P-Channel MOSFET for power polarity protection.

Thanks for your input.

Phone or usb chargers are often poorly regulated. I have one of these:


And as you can, see there is over 1/4V of sag under load. This is typical of a "soft" power supply.

You do not need the pot on the output to be part of the filtering circuit, it needs to be a volume control. How you have it now ( post #10) is wrong. It should be more like the original notes and volts circuit. You should never put any DC path on an audio output, it should always end in a capacitor. The MIDI input should not have a capacitor in the circuit as this is a pure digital input.

Thank you for posting the code but could you please post it correctly for this forum.
Read How to get the best from this from this Forum where it tells you how to post code here.

Basically, edit post#10, by clicking on the pencil icon at the end of that post. Now select all the code, even if it goes over multiple pages, and then click the </> icon on the top bar and save the edit by hitting the reply button. Alternately when you copied the code from the Arduino IDE you should have used the "copy for forum" option and then you could have posted this directly into your post while you were composing it.

Ok, thanks. I edited the audio output from pin D3 with:
audioOut_Auduino

Is my volume pot still not good?
Thanks again,
TonyAm

Yes it is still not good. The last thing the output should be connected to is a capacitor.

This would be better:-

Could be from a long/thin USB lead.
Try a short/fat one, used for high-drain devices like portable hard drives.
Leo..

Isn't the cable, its the source. With that probe, I've tested an assortment of USB chargers, and the majority of them are poorly regulated.