Arduino-Pedal-Effects/c/New Effects PedalSHIELD UNO/Bell_Shifter/Bell_Shifter.ino
2022-07-18 18:23:07 +02:00

128 lines
4 KiB
C++

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