Code:
/* Multi Fx by Diodac
Set effect button on pin 2
0 = clean
1 = ring_mod_fx
2 = pitch_fx
3 = reverb_fx
4 = flange_fx
5 = chorus_fx
Set level of effect potentiometer on A0
Set level of volume potentiometer on A1
Set level of dry/wet potentiometer on A2
*/
IntervalTimer timer;
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce2.h>
// GUItool: begin automatically generated code
AudioInputI2S i2s1Record; //xy=609,170
AudioMixer4 mixer1; //xy=754,183
AudioPlayQueue queuePlay; //xy=876,410
AudioRecordQueue queueRecord; //xy=897,184
AudioMixer4 mixer2; //xy=1032,429
AudioOutputI2S i2s2Play; //xy=1216,429
AudioConnection patchCord1(i2s1Record, 0, mixer1, 0);
AudioConnection patchCord2(i2s1Record, 1, mixer1, 1);
AudioConnection patchCord3(mixer1, queueRecord);
AudioConnection patchCord4(mixer1, 0, mixer2, 1);
AudioConnection patchCord5(queuePlay, 0, mixer2, 0);
AudioConnection patchCord6(mixer2, 0, i2s2Play, 0);
AudioConnection patchCord7(mixer2, 0, i2s2Play, 1);
AudioControlSGTL5000 sgtl5000_1; //xy=923,106
// GUItool: end automatically generated code
#define BUTTON_PIN 2
#define LED_PIN 13
Bounce change_fx = Bounce();
elapsedMillis delayMillis;
elapsedMillis delayControl;
#define MAX_SAMPLES 128
#define MAX_QUEUE_SIZE 8
#define bufferSize 48000
#define bias 512
short FASTRUN buffer[bufferSize];
short FASTRUN bufferIn[MAX_SAMPLES * MAX_QUEUE_SIZE];
short FASTRUN bufferOut[MAX_SAMPLES * MAX_QUEUE_SIZE];
int16_t queue_offset = 0, pointer = 0;
volatile float volumeControl = 0, wet = 0, dry = 0;
volatile int level = 0;
byte switchEffect = 0;
//Oscillators
#define points 16383
unsigned int FASTRUN modulation[points];
//For Flange & Shifters++++++++++++++++++++
#define MIN 2 //~60us distance
#define MAX 400 //~ 8.5ms distance
#define SIZE 400
#define pitch 11700
byte dir = 1;
unsigned int utime = 0, offset = 0, increment = 0, divider = 0, distance = 0, fractional = 0x00;
int speed = 0, sample = 0, time = 0;
int32_t resultA = 0, resultB = 0, outputA = 0, outputB = 0;
//Modulators & Wobbies+++++++++++++++++++++++++++
#define space 350
#define maximum 300
unsigned int wave = bias;
int modulation_in = 0;
int FASTRUN AB[maximum];
int32_t delay_line = 0, line_A = 0, line_B = 0, calculator = 0, fraction = 0;
double down = -0.6, down1 = -0.98, down2 = -0.8;
double up = 0.6, up1 = 0.98, up2 = 0.8;
//Reverb+++++++++++++++++++++++++++++
#define D1 4000
#define D2 4000
#define D3 4000
#define D4 4000
#define D5 10000
#define D6 4000
int DV1 = 100;
int DV2 = 100;
int DV3 = 150;
int DV4 = 200;
int DV5 = 400;
int DV6 = 200;
double x1 = 0.69, x2 = 0.64, x3 = 0.59, x4 = 0.54;
double y_1 = 0.99 , y_2 = 0.94 , y_3 = 0.89 , y_4 = 0.84;
short FASTRUN X1[D1];
short FASTRUN X2[D2];
short FASTRUN X3[D3];
short FASTRUN X4[D4];
short FASTRUN X5[D5];
short FASTRUN X6[D6];
double S1 = 0, S2 = 0, S3 = 0, S4 = 0, S5 = 0, S6 = 0, S7 = 0;
int32_t DC1 = 0, DC2 = 0, DC3 = 0, DC4 = 0, DC5 = 0, DC6 = 1, DC7 = 1, DC8 = 0;
// Multi ++++++++++++++++++++
inline uint32_t M32x16(uint32_t x, uint32_t y) {
return (uint32_t)(((uint32_t)x) * ((uint32_t)y) >> 16);
}
void setup() {
Serial.begin(115200);
AudioMemory(32);
pinMode(14, INPUT_DISABLE);
pinMode(15, INPUT_DISABLE);
pinMode(16, INPUT_DISABLE);
pinMode(17, INPUT_DISABLE);
pinMode(22, INPUT_DISABLE);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
change_fx.attach(BUTTON_PIN);
change_fx.interval(15);
modulation_oscillator();
timer.begin(effect, 22.676);
timer.priority(128);
sgtl5000_1.enable();
sgtl5000_1.volume(1.0);
sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
sgtl5000_1.micGain(25);
//sgtl5000_1.lineInLevel(15);
//sgtl5000_1.lineOutLevel(15);
mixer1.gain(2, 0);
mixer1.gain(3, 0);
mixer2.gain(2, 0);
mixer2.gain(3, 0);
queuePlay.setBehaviour(AudioPlayQueue::NON_STALLING);
queuePlay.setMaxBuffers(8);
queueRecord.begin();
}
void modulation_oscillator() {
for (int i = 0; i < points; i++)
modulation[i] = (0.99 * cos(((2.0 * PI) / points) * i));
}
void i2s() {
memcpy(&bufferIn[queue_offset], queueRecord.readBuffer(), 256);
queueRecord.freeBuffer();
int16_t *output = queuePlay.getBuffer();
memcpy(output, &bufferOut[queue_offset] , 256);
queue_offset += MAX_SAMPLES;
while (queue_offset >= (MAX_SAMPLES * MAX_QUEUE_SIZE)) queue_offset = 0;
queuePlay.playBuffer();
}
void loop() {
while (delayControl >= 50) {
delayControl = 0;
mixer1.gain(0, volumeControl);
mixer1.gain(1, volumeControl);
mixer2.gain(0, wet);
mixer2.gain(1, dry);
}
if (digitalRead(BUTTON_PIN) == LOW) {
digitalWrite(LED_PIN, HIGH );
} else digitalWrite(LED_PIN, LOW );
}
void effect() {
while (queueRecord.available()) i2s();
while (delayMillis >= 50) {
delayMillis = 0;
level = map(analogRead(A0), 0, 1023, 0, 1023);
volumeControl = map(analogRead(A1), 0, 1023, 0, 1000);
volumeControl = volumeControl / 1000.0;
int val = map(analogRead(A2), 0, 1023, 0, 1000);
wet = (float)val;
wet = wet / 1000.0;
dry = (float)map(val, 0, 1000, 10, 0);
dry = dry / 10.0;
change_fx.update();
if (change_fx.rose()) {
switchEffect = switchEffect + 1.0;
}
}
if (switchEffect >= 6) switchEffect = 0;
switch (switchEffect) {
case 0:
clean();
break;
case 1:
ring_mod_fx();
break;
case 2:
pitch_fx();
break;
case 3:
reverb_fx();
break;
case 4:
flange_fx();
break;
case 5:
chorus_fx();
break;
}
}
void clean() {
pointer++;
while (pointer >= (MAX_SAMPLES * MAX_QUEUE_SIZE)) pointer = 0;
bufferOut[pointer] = bufferIn[pointer];
}
void ring_mod_fx() {
static long buffIn = bufferSize, buffOut = bufferSize - time;
pointer++;
while (pointer >= (MAX_SAMPLES * MAX_QUEUE_SIZE)) pointer = 0;
time = map(level, 0, 1023, 330, 1);
buffer[buffIn] = bufferIn[pointer];
buffIn++;
if (buffIn >= space) buffIn = 0;
buffOut = buffIn + offset;
if (buffOut >= space) buffOut -= space;
bufferOut[pointer] = buffer[buffOut];
if (dir) {
if (offset >= (space - (unsigned int)time)) {
dir = 0;
offset--;
}
else offset++;
}
else {
if (offset <= 4) {
dir = 1;
offset--;
}
else offset -= 1;
}
}
void pitch_fx() {
static unsigned int locationIn = SIZE, locationOut = SIZE - fractional;
pointer++;
while (pointer >= (MAX_SAMPLES * MAX_QUEUE_SIZE)) pointer = 0;
buffer[locationIn] = bufferIn[pointer];
locationIn++;
if (locationIn >= SIZE) locationIn = 0;
locationOut = locationIn + offset;
if (locationOut >= SIZE) locationOut -= SIZE;
outputA = buffer[locationOut];
locationOut += (SIZE >> 1);
if (locationOut >= SIZE) locationOut -= SIZE;
outputB = buffer[locationOut];
if (offset > (SIZE >> 1)) distance = SIZE - offset;
else distance = offset;
resultA = M32x16(outputA, (distance << 7));
resultB = M32x16(outputB, (((SIZE >> 1) - distance) << 7));
bufferOut[pointer] = resultA += resultB;
if (level > bias) {
fractional += map(level, 511, 1023, 0, 63);
if (fractional >= 0x0080) {
offset += (fractional >> 7);
fractional &= 0x007f;
}
if (offset >= SIZE) offset -= SIZE;
} else if (level < bias) {
fractional += map(level, 0, 511, 63, 0);
if (fractional >= 0x0080) {
offset -= (fractional >> 7);
fractional &= 0x007f;
}
if (offset >= SIZE) offset += SIZE;
}
}
void reverb_fx() {
pointer++;
while (pointer >= (MAX_SAMPLES * MAX_QUEUE_SIZE)) pointer = 0;
DV1 = map(level, 0, 1023, 100, 4000);
DV2 = map(level, 0, 1023, 100, 4000);
DV3 = map(level, 0, 1023, 150, 4000);
DV4 = map(level, 0, 1023, 200, 4000);
DV5 = map(level, 0, 1023, 400, 10000);
DV6 = map(level, 0, 1023, 200, 4000);
X1[DC1] = (bufferIn[pointer] + x1 * X1[DC1] / 1.2);
X2[DC2] = (bufferIn[pointer] + x2 * X2[DC2] / 1.4);
X3[DC3] = (bufferIn[pointer] * X3[DC3] / 1.6);
X4[DC4] = (bufferIn[pointer] * X4[DC4] / 1.8);
S1 = y_1 * X1[DC1];
S2 = y_2 * X2[DC2];
S3 = y_3 * X3[DC3];
S4 = y_4 * X4[DC4];
DC1++; if (DC1 >= DV1) DC1 = 0;
DC2++; if (DC2 >= DV2) DC2 = 0;
DC3++; if (DC3 >= DV3) DC3 = 0;
DC4++; if (DC4 >= DV4) DC4 = 0;
S5 = (S1 + S2 + S3 + S4) / 4;
X5[DC7] = (S5 + x3 * X5[DC5]);
S6 = -x3 * X5[DC7] + X5[DC5];
DC5++; if (DC5 >= DV5) DC5 = 0;
DC7++; if (DC7 >= D5) DC7 = 0;
X6[DC8] = (S6 + x4 * X6[DC6]);
S7 = (-x4 * X6[DC8] + X6[DC6]);
DC6++; if (DC6 >= DV6) DC6 = 0;
DC8++; if (DC8 >= D6) DC8 = 0;
bufferOut[pointer] = (int16_t)S7;
}
void flange_fx() {
static int locationIn = SIZE, locationOut = SIZE - fractional;
pointer++;
while (pointer >= (MAX_SAMPLES * MAX_QUEUE_SIZE)) pointer = 0;
buffer[locationIn] = bufferIn[pointer];
locationIn++;
if (locationIn >= SIZE) locationIn = 0;
locationOut = locationIn - (fractional >> 8);
if (locationOut < 0) locationOut += SIZE;
outputA = buffer[locationOut] + bufferIn[pointer];
locationOut -= 1;
if (locationOut < 0) locationOut += SIZE;
outputB = buffer[locationOut] + bufferIn[pointer];
resultA = M32x16(outputA, ((0xff - (fractional & 0x00ff)) << 7));
resultB = M32x16(outputB, ((fractional & 0x00ff) << 7));
bufferOut[pointer] = (resultA += resultB);
int shift = level >> 6;
if (shift >= 11) shift = 11;
if (dir) {
if ((fractional >> 8) >= MAX) dir = 0;
fractional += (1 + shift);
}
else {
if ((fractional >> 8) <= MIN) dir = 1;
fractional -= (1 + shift);
}
}
void chorus_fx() {
pointer++;
while (pointer >= (MAX_SAMPLES * MAX_QUEUE_SIZE)) pointer = 0;
modulation_in = (2 + (level >> 3));
delay_line = modulation_in / 2;
for (int index = 0; index <= modulation_in; index++)
AB[modulation_in + 1 - index] = AB[modulation_in - index];
AB[0] = up * bufferIn[pointer] + down * AB[delay_line];
line_A = delay_line - delay_line * modulation[calculator * 2];
line_B = int32_t(line_A);
fraction = line_A - line_B;
if (fraction == 0) fraction = 0.01;
if (fraction == 1) fraction = 0.99;
calculator++;
if (calculator * 2 >= points) calculator = 0;
bufferOut[pointer] = (int32_t)(AB[line_B + 1] * fraction + AB[line_B] * (1 - fraction));
}