/* Based on the "stomp_shifter" from openmusiclabs; this is a pitch shifter program. it indexes through a sample buffer at either a slower or faster rate than the incoming samples. the buffer boundaries are dealt with by having to samples being played back simultaneously, each from opposite sides of the buffer. the volume of each is set by the distance to the boundary. the rotary encoder sets the speed of playback. */ #include "mult16x16.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 #define SIZE 1000 // make this smaller if it clicks int buffer[SIZE]; // sample buffer unsigned int location = 0; // current sample input position unsigned int offset = 0; // playback sample offset from input byte shift = 0x80; unsigned int fractional = 0x80; // fractional sample rate int data_buffer = 0x80; int counter=0; int toggle_position=0; 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() { //Turn on the LED if the effect is ON. if (digitalRead(FOOTSWITCH)) digitalWrite(LED, HIGH); else digitalWrite(LED, LOW); //nothing else here, all happens in the Timer 1 interruption. } ISR(TIMER1_CAPT_vect) { // output data OCR1AL = ((data_buffer >> 8) + 0x80); OCR1BL = data_buffer; // output the bottom 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 counter++; //the pushbuttons are checked every 2500 times. if(counter==2500) { counter=0; if (!digitalRead(PUSHBUTTON_2)) { shift++; if (shift >= 0xfe) shift = 0xfe; } if (!digitalRead(PUSHBUTTON_1)) { shift--; if (shift <= 1) shift = 1; } } //Depending on the Toggle switch position, the effect is reseted) if(digitalRead(TOGGLE)!=toggle_position) { toggle_position = digitalRead(TOGGLE); //update the new value shift=0x80; } buffer[location] = input; // store incoming data location++; // increment storage location if (location >= SIZE) location = 0; // boundary wrap unsigned int temp = location + offset; // find next sample if (temp >= SIZE) temp -= SIZE; // boundary wrap int output = buffer[temp]; // fetch sample temp += (SIZE >> 1); // find sample on opposite side of buffer if (temp >= SIZE) temp -= SIZE; // boundary wrap int output2 = buffer[temp]; // fetch sample unsigned int distance; // find distance to buffer boundary if (offset > (SIZE >> 1)) distance = SIZE - offset; else distance = offset; int result; // average the 2 samples based on distance to boundary MultiSU16X16toH16(result, output, (distance << 7)); MultiSU16X16toH16(output, output2, (((SIZE >> 1) - distance) << 7)); output += result; fractional += shift; // increment offset if (fractional >= 0x0080) { offset += (fractional >> 7); fractional &= 0x007f; } if (offset >= SIZE) offset -= SIZE; // boundary wrap // save data data_buffer = output; }