#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
AudioEffectTapeDelay10tap delay1;
AudioInputUSB usb1;
AudioEffectGranular granular1;
AudioOutputI2S i2s2; //unconnected
AudioOutputUSB usb2;
AudioMixer4 mixer1;
AudioMixer4 mixer2;
AudioMixer4 mixer3;
AudioConnection patchCord10(usb1, 0, mixer3, 0); //input stereo to mono
AudioConnection patchCord11(usb1, 1, mixer3, 1);
AudioConnection patchCord12(mixer3, 0, granular1, 0);
AudioConnection patchCord1(granular1, 0, mixer1, 0); //granular object into delay input mixer
AudioConnection patchCord3(mixer1, delay1);
AudioConnection patchCord4(mixer3, 0, mixer1, 2); //dry signal to delay (no granular)
AudioConnection patchCord5(delay1, 0, mixer2, 0);
//AudioConnection patchCord6(delay1, 1, mixer2, 1); //extra delay taps (unused)
//AudioConnection patchCord7(delay1, 2, mixer1, 2);
AudioConnection patchCord8(mixer2, 0, usb2, 0);
AudioConnection patchCord9(mixer2, 0, usb2, 1);
AudioConnection patchCord13(mixer2, 0, mixer1, 1); //delay feedback
////////////////////////midi
#if defined(USBCON)
#include <midi_UsbTransport.h>
static const unsigned sUsbTransportBufferSize = 16;
typedef midi::UsbTransport<sUsbTransportBufferSize> UsbTransport;
UsbTransport sUsbTransport;
MIDI_CREATE_INSTANCE(UsbTransport, sUsbTransport, MIDI);
#endif
#include <MIDI.h>
///
#define GRANULAR_MEMORY_SIZE 12800 // enough for 290 ms at 44.1 kHz
int16_t granularMemory[GRANULAR_MEMORY_SIZE];
#define DELAY_MAX_LEN 22050 // buffer for samples @44100 samples per second, 22050 = 0.5s
int16_t sample_delay_line[DELAY_MAX_LEN] = {};
float response = 0.9; //this sets the response time of the delay/pitch slider. higher value = slower response.
int16_t dtime = 100;
float itime = 3.0;
float ptch = 100.0;
int fvalue; //for midi control
double mvalue;
void doControlChange(byte channel, byte control, byte value) {
mvalue = (double)value/127.0;
if(control==1){ //if new midi control signal is received, update delay time and pitch
fvalue = (int16_t)map(value, 0,127,0,500); //midi cc is 0-127
dtime = fvalue;
delay1.delayfade(0, dtime, itime);
int tptch = (int16_t)map(value, 0,127,100,8000); //arbitrary values, to be fine-tuned
ptch = tptch/100.0;
}
if(control==2){ //feedback
mixer1.gain(1, mvalue);
}
}
void setup(void) {
Serial.begin(9600);
usbMIDI.begin();
usbMIDI.setHandleControlChange(doControlChange);
AudioMemory(150 * (128 / AUDIO_BLOCK_SAMPLES));
mixer1.gain(0, 0.7);
mixer1.gain(1, 0.0);
//still need to set mixer gains for delay taps (there are currently three connected, only one in use)
// initialise the delayline
delay1.begin(sample_delay_line, DELAY_MAX_LEN);
delay1.delayfade(0, dtime, itime);
granular1.begin(granularMemory, GRANULAR_MEMORY_SIZE);
granular1.beginPitchShift(290.0); // can experiment with longer (this is set once in setup)
}
void loop(void) {
usbMIDI.read();
rateofchange();
}
elapsedMillis oTime;
void updatei(){
if (oTime > 30) {
dtime = lowpass_d_d(fvalue);
delay1.delayfade(0, dtime, itime);
oTime=0;
}
}
elapsedMillis rTime;
float x = 0.0;
float y = 0.0;
float pitchShift;
void rateofchange(){
if (rTime > 30) {
y = ptch;
float rateOfChange = (x - y);
rTime=0;
x = ptch;
pitchShift = lowpass_d_d(rateOfChange);
if (pitchShift < 0.1 && pitchShift > -.1){ //the granular effect introduces some subtle stuttering when passing audio. when there's no effect, pass dry audio.
//granular1.stop();
mixer1.gain(0,0.0); //mute granular effect
mixer1.gain(2,1.0); //pass dry audio
}
else {
mixer1.gain(0,1.0); //enable granular effect
mixer1.gain(2,0.0); //mute dry audio
granular1.setSpeed(pitchShift+1.0); //right now there is a big negative swing (which is approx -3 to 3 when its quick) which should be offset to 0.1 to 8
}
//Serial.print("\t");
Serial.print(pitchShift);
//Serial.print("\t");
//Serial.println(rateOfChange);
}
}
float LPhistory;
float LPout;
float lowpass_d_d(int input) { //this is a simple interpolating lowpass filter to slow down the response of the pitch/delay slider
float LPhistory = (input + (response * (LPout - input)));
LPout = LPhistory;
return LPout;
}