This Arduino-based 4 step sequencer uses the popular Auduino code as synthesiser, with some simple additions to add a sequencer to the code (see below). When i was experimenting with the Atari Punk Console 8-step sequencer described here, i was not too impressed with the sound and remembered the Auduino. So i went back to the Auduino to build my sequencer. Here’s how it sounds:

The original Auduino has 5 potentiometers to modify its sound. One of them is SYNC_CONTROL which controls the base pitch of the sound. I started with a standard Arduino UNO, which only has 6 analog inputs. So i could only use 1 potentiometer per step, for the pitch, and keep the other 4 Auduino parameters constant for the 4 steps. I also needed one potentiometer for the tempo, so only 1 left for extra Auduino effects, which i decided to connect to GAIN_FREQ_CONTROL. For the other 3 parameters that are controlled by a potentiometer on the original Auduino, i used a constant.

So my first prototype on a breadboard had 6 potentiometers (pitch for 4 steps, effect, tempo), and 4 LEDs, connected to an Arduino UNO. I connected the output to a simple speaker.

Next step was to put the pots in a nice laser cut panel with soldered connections, and i also added a small mono amplifier to drive a larger speaker, with a volume pot. This speaker is a little damaged so the Auduino sounds is not as pure as usual, but it adds character.

img_20160906_090337828_hdr

I switched to an Arduino Nano that easily fits onto a breadboard. By now i was hooked to this little instrument so i decided to put it in a nice permanent laser cut box. I swapped the breadboard for a perf board and soldered female headers to it for the Arduino Nano. The (mono) output pin goes over a 150Ω resistor to a 3.5mm jack connection to plug it into any type of external speaker. It also goes through a 10KΩ volume pot and a capacitor to filter out the DC, as input for the small mono amplifier. This amplifier, connected to the internal speaker, can be powered on/off with a switch on the panel.

img_20160908_111445026

Then i fixed the LEDs, amplifier, and connectors with hot glue and put the box together. The Arduino and amplifier are powered by a mini USB cable connected to the Arduino, so it works with any USB power supply, such as a powerbank. The tabs have a very close fit so it looks like i won’t need any glue to hold the box together.

img_20160908_112309941

And with some colourful knobs i had laying around:

img_20160916_125753362_hdr

And i made a custom PCB for this project, and got some of my kid students to make their own box at DSL.

image1

/*
 Auduino, the Lo-Fi granular synthesiser https://code.google.com/archive/p/tinkerit/downloads
 added a 4 step sequencer inspired by https://learn.sparkfun.com/tutorials/build-an-auduino-step-sequencer
 Tom Tobback Sep 2016
 BuffaloLabs www.cassiopeia.hk/kids

 LICENSE:
 Copyright (c) 2016 Tom Tobback 

 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/* analog inputs:
 * A0 pitch step 1 (syncPhaseInc)
 * A1 pitch step 2
 * A2 pitch step 3
 * A3 pitch step 4
 * A4 tempo
 * A5 effect (grainPhaseInc)
 * plus volume potentiometer
 *
 * audio out via 220 ohm resistor to 3.5mm jack
 * audio out via 10K/10K voltage divider and 10K volume pot and 10uF cap to internal mono amp with speaker
 * power switch on amp
 * built with Arduino Nano on perf board powered by USB cable
 */

#include <avr/io.h>
 #include <avr/interrupt.h>

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;

// Changing these will also requires rewriting audioOn()

#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__) || defined(__AVR_ATmega2560__)
 //
 // 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[] = {
 17, 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[(1023 - input) >> 3]);
 }

// 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]);
 }

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
 }

long counter = 0;
 long tempo;
 int pattern = 0;

const byte pat0 = 4;
 const byte pat1 = 5;
 const byte pat2 = 6;
 const byte pat3 = 7;

void setup() {
 pinMode(PWM_PIN, OUTPUT);
 audioOn();
 pinMode(LED_PIN, OUTPUT);

pinMode(pat0, OUTPUT);
 pinMode(pat1, OUTPUT);
 pinMode(pat2, OUTPUT);
 pinMode(pat3, OUTPUT);
 digitalWrite(pat0, LOW);
 digitalWrite(pat1, LOW);
 digitalWrite(pat2, LOW);
 digitalWrite(pat3, LOW);

// presets for 3 less important pots
 grainDecay = 200 / 8;
 grain2PhaseInc = mapPhaseInc(200) / 2;
 grain2Decay = 200 / 4;
 }

void loop() {

tempo = map(analogRead(A4), 0, 1023, 100, 4000);
 counter++;
 if (counter > tempo) {
 counter = 0;
 if (pattern == 4) {
 pattern = 0;
 }
 switch (pattern) {
 case 0:
 syncPhaseInc = mapPentatonic(analogRead(A0));
 digitalWrite(pat3, LOW);
 digitalWrite(pat0, HIGH);
 break;
 case 1:
 syncPhaseInc = mapPentatonic(analogRead(A1));
 digitalWrite(pat0, LOW);
 digitalWrite(pat1, HIGH);
 break;
 case 2:
 syncPhaseInc = mapPentatonic(analogRead(A2));
 digitalWrite(pat1, LOW);
 digitalWrite(pat2, HIGH);
 break;
 case 3:
 syncPhaseInc = mapPentatonic(analogRead(A3));
 digitalWrite(pat2, LOW);
 digitalWrite(pat3, HIGH);
 break;
 }

grainPhaseInc = mapPhaseInc(analogRead(A5)) / 2;
 pattern++;
 }
 }

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;
 }

2 thoughts on “Auduino 4-step sequencer

Leave a Reply

Your email address will not be published. Required fields are marked *