/* Based on the flanger from openmusiclabs.com
this program does a flanger effect, and interpolates between samples
for a smoother sound output.  a rampwave is used to set the variable
delay.  the min and max delay times it swing between is set by MIN
and MAX.  these are in samples, divide by 31.25ksps to get ms delay
times.  the push buttons determines how much the ramp increments
by each time.  this sets the frequency of the delay sweep, which is
min/maxed by B_MIN/B_MAX.
*/

#include "mult16x8.h"

//defining harware resources.
#define LED 13
#define FOOTSWITCH 12
#define TOGGLE 2
#define PUSHBUTTON_1 A5
#define PUSHBUTTON_2 A4

//defining the output PWM parameters
#define PWM_FREQ 0x00FF // pwm frequency - 31.3KHz
#define PWM_MODE 0 // Fast (1) or Phase Correct (0)
#define PWM_QTY 2 // 2 PWMs in parallel

//defining FX parameters
#define MIN 2 // min delay of ~60us
#define MAX 200 // max delay of ~6ms
#define SIZE MAX+10 // data buffer size - must be more than MAX


int buffer[SIZE]; // create a data buffer
byte dir = 1; // keeps track of up/down counting
unsigned int location = 0; // incoming data buffer pointer
byte button; // button checking timer
byte counter = 4; // button counter (and start value)
unsigned int fractional = 0x00; // fractional sample position
int data_buffer; // temporary data storage to give a 1 sample buffer

int toggle_position=0;
int counter2=0; //buttons timer counter


void setup() {
  //setup IO
  pinMode(FOOTSWITCH, INPUT_PULLUP);
  pinMode(TOGGLE, INPUT_PULLUP);
  pinMode(PUSHBUTTON_1, INPUT_PULLUP);
  pinMode(PUSHBUTTON_2, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
  
  // setup ADC
  ADMUX = 0x60; // left adjust, adc0, internal vcc
  ADCSRA = 0xe5; // turn on adc, ck/32, auto trigger
  ADCSRB = 0x07; // t1 capture for trigger
  DIDR0 = 0x01; // turn off digital inputs for adc0

  // setup PWM
  TCCR1A = (((PWM_QTY - 1) << 5) | 0x80 | (PWM_MODE << 1)); //
  TCCR1B = ((PWM_MODE << 3) | 0x11); // ck/1
  TIMSK1 = 0x20; // interrupt on capture interrupt
  ICR1H = (PWM_FREQ >> 8);
  ICR1L = (PWM_FREQ & 0xff);
  DDRB |= ((PWM_QTY << 1) | 0x02); // turn on outputs
  sei(); // turn on interrupts - not really necessary with arduino
  }

void loop() {
  if (digitalRead(FOOTSWITCH)) digitalWrite(LED, HIGH); 
    else  digitalWrite(LED, LOW);}






ISR(TIMER1_CAPT_vect) { // all processing happens here

  // output the last value calculated
  OCR1AL = ((data_buffer + 0x8000) >> 8); // convert to unsigned, send out high byte
  OCR1BL = data_buffer; // send out low byte
  
  // get ADC data
  byte temp1 = ADCL; // you need to fetch the low byte first
  byte temp2 = ADCH; // yes it needs to be done this way
  int input = ((temp2 << 8) | temp1) + 0x8000; // make a signed 16b value

//BUTTONS
  counter2++; //to save resources, the pushbuttons are checked every 2000 times.
if(counter2==2000)
{ 
counter2=0;
  if (!digitalRead(PUSHBUTTON_1)) {
     if (counter > MIN) counter-=1; // if not at min, decrement
      }
      if (!digitalRead(PUSHBUTTON_2)) {
        if (counter < MAX) counter+=1; // if not at max, increment
      }

//toggle switch
{
toggle_position = digitalRead(TOGGLE);
    }
  }
  
  
  // fetch/store data
  buffer[location] = input; // store current sample
  location++; // go to next sample position
  if (location >= SIZE) location = 0; // deal with buffer wrap
  int temp = location - (fractional >> 8); // find delayed sample
  if (temp < 0) temp += SIZE; // deal with buffer wrap
  int output = buffer[temp]; // fetch delayed sample
  if (toggle_position=1) output = buffer[temp]+input;
  if (toggle_position=0) output = buffer[temp];
  temp -= 1; // find adjacent sample
  if (temp < 0) temp += SIZE; // deal with buffer wrap
  int output2 = buffer[temp]; // get adjacent sample
  if (toggle_position=1) output2 = buffer[temp]+input;
  if (toggle_position=0) output2 = buffer[temp];
  
  // interpolate between adjacent samples
  int temp4; // create some temp variables
  int temp5;

  // multiply by distance to fractional position
  MultiSU16X8toH16(temp4, output, (0xff - (fractional & 0x00ff)));
  MultiSU16X8toH16(temp5, output2, (fractional & 0x00ff));
  output = temp4 + temp5; // sum weighted samples
  
  // save value for playback next interrupt
  data_buffer = output; 
  
  // up or down count as necessary till MIN/MAX is reached
  if (dir) {
    if ((fractional >> 8) >= MAX) dir = 0;
    fractional += counter;
  }
  else {
    if ((fractional >> 8) <= MIN) dir = 1;
    fractional -= counter;;
  } 
}