How to Make (almost) Anything

Final Project

Programmable, portable, and remotely controllable guitar preamp/effector that plugs into a guitar. The input signal from guitar is processed by the effector which can drive either an amp speaker or a headphone. It has Bluetooth connectivity that allows a wireless device e.g. smartphone or laptop to control the effector remotely.

Working video:

Final product:

CIRCUIT

The circuit includes ATTiny44 for processing the input signal, LM386 for driving headphones, and Bluesmirf Bluetooth module for wireless connectivity. I used ATTiny44's differential ADC with 20x gain to get good dynamic range for input signal from the guitar.

The parts to be connected: 9v battery, 1/4" input/output, 1/8" output, potentiometer for volume control, and a Bluetooth module. 

Generations of the circuit design. From old (left) to new (right).

SOFTWARE

Arduino code:


#include <SoftwareSerial.h>
#define rxPin 0
#define txPin 1
SoftwareSerial mySerial(rxPin, txPin);

unsigned char inputLo, inputHi;
int inputRaw;
unsigned short output;

int preset;

//effect
int fx;
int j, value50, value300, value10000, delayed;

//chorus
unsigned char buffer[128];
byte Progress;
boolean Direction;
byte Offset;
byte Position;
unsigned short SinceNudge;
unsigned short SinceUpdate;
unsigned short NudgeLength;

//audio processing
int iw;
byte bb;
int icnt;
int iw1;

volatile byte Timewaster;

void setup()
{
  CLKPR = (1 << CLKPCE);
  CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);

  TCCR0A = ((0 << COM0A0) | (1 << COM0A1) | (0 << COM0B0) | (1 << COM0B1) | (1 << WGM01) | (1 << WGM00));
  TCCR0B = (1 << CS00); // set timer 0 prescalar to 1

  pinMode( 8, OUTPUT);
  pinMode( 7, OUTPUT);
  analogWrite( 8, 0 );
  analogWrite( 7, 0 );

  ADMUX = (0 << REFS1) | (0 << REFS0) // 5V ref
        | (1 << MUX5) | (1 << MUX4) | (0 << MUX3) | (0 << MUX2) | (0 << MUX1) | (1 << MUX0);
  ADCSRA = (1 << ADEN) // enable
         | (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0); // prescaler /64
  ADCSRB = (1 << BIN); // bipolar mode

  /* Give it four cycles to sink in. */
  Timewaster++;
  Timewaster--;
  Timewaster++;
  Timewaster--;

  //init value
  j = 50;
  value50 = 50;
  value300 = 300;
  value10000 = 10000;
  delayed = 0;

  Progress = 0;
  Direction = 0;
  Offset = 0;
  SinceNudge = 0;
  SinceUpdate = 0;
  NudgeLength = 0;

  preset = 1;
  mySerial.begin(115200);
}

void loop()
{
  if (mySerial.available()){
    preset = mySerial.read() - 48;
  }
  fx = 100;

  if(preset==0){ //bypass
    readInput();
    outputInt(inputRaw, 5, 1024); //16 bit out
  }
  else if(preset==1){ //distortion
    readInput();
    outputInt((unsigned char)((inputRaw+512)<<3), 5, 0); //16 bit out
  }
  else if(preset==2){ //phasor
    readInput();
    NudgeLength = 128;
    inputRaw += 512;
    inputRaw>>=1;

    if(Progress<128) buffer[ Progress ] = inputRaw;
    Progress++;
    if(Progress>127) Progress = 0;

    if( SinceNudge ) SinceNudge--; else
    {
      if( Direction )
      {
        Offset++;
        if( Offset == 128 ){ Offset = 127; Direction = 0; }
      }
      else
      {
        Offset--;
        if( Offset == 255 ){ Offset = 0; Direction = 1; }
      }
      SinceNudge = NudgeLength;
    }

    Position = Progress + Offset;
    while(Position>127) Position -= 128;
    if(Position<128) inputRaw += buffer[ Position ];

    outputInt(inputRaw, 6, 0); //16 bit out
  }
  else if(preset==3){ //bit crush
    value300 = 1 + ((float) fx / (float) 3);
    readInput();
    if(delayed > value300) {
      unsigned int input = (inputRaw<<6) + 32768;
      input = (input >> 8 << 8);
      outputInt(input, 0 , -32768);
      delayed = 0;
    }
    delayed++;
  }
  else if(preset==4){ //customize your own sound
    value50 = 1 + ((float) fx / (float) 20);
    readInput();
    outputInt((inputRaw<<6 + 32768)*value50, 0, -32768);
  }
}

/*
I/O for full scale int
*/
void outputInt(int val, int scale, int offset){
  output = (val + offset)<<scale;
  analogWrite( 8, output >> 8 );
  analogWrite( 7, output & 255 );
}
void readInput(){
  /* get input */
  delay(2); // Wait for Vref to settle
  ADCSRA |= (1 << ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));

  inputLo = ADCL;
  inputHi = ADCH;

  // rearragne bits
  inputRaw = 256*inputHi + inputLo;
  if (inputRaw > 511){
    inputRaw -= 1024;
  }
}


iPhone application for controlling the effects

CASE

Two parts of the case slide and snap into each other. Very sturdy, no hinges needed.

Testing how the connectors can be installed.

PUTTING TOGETHER

Copyright © 2014 Sang-won Leigh