#include <Wire.h>
#include <Adafruit_MCP4725.h>
#include <SimpleTimer.h>
Adafruit_MCP4725 dac60; // OUT JACK
const byte DAC_address = 0x60; // OUT JACK
#define VOCT_IN_PIN A0 // IN POT
#define TUNE_IN_POT A1 // IN POT
#define LOWER_IN_POT A2 // IN POT
#define SCALE_IN_PIN A3 // IN POT //1C mag, , 2C min, 3 min mel, 4 7th, 5 jazz, 6 Maj Pentatonic, 7 Min Pentatonic
#define CLOCK_BMP A4 // IN POT
#define CLOCK_PERCENTAGE A5 // IN POT
#define TUNE_FROM_MCP4725 A6
#define TRIGGER_IN_PIN 7 // IN JACK
#define CLOCK_LED 13 // OUT JACK
int CLOCK_INOUT;
// CONFIGURATION
int usescale=1; // 1=use scale selecting by pot SCALE_IN_PIN 0 = use pots -1= use input from MCP4725
int random_mysound=0; // 1=random in scale; 0=use pots VOCT_IN_PIN & TUNE_IN_POT
int internal_clock=2; // 1=external trigger 2=internal clock by pots 3=random clock
#define MIN_BPM 50
#define MAX_BPM 440
#define MIN_PERCENTAGE 0
#define MAX_PERCENTAGE 90
#define CALIBRATE_MAX_POT 890
#define OCT_RANGE 10
#define VOCT_SCALE 1.0
#define KNOB_SCALE 1.0
#define BASE_OCTAVE 8
#define NB_SMOOTHING 5
int myscale;
int old_myscale;
int mysound;
int old_mysound;
int pot_clockINOUT;
SimpleTimer timer;
int count = 0;
int input_BMP;
int input_PERCENTAGE;
float readings[NB_SMOOTHING];
int readIndex = 0;
float total = 0;
float average = 0;
float freq;
float volt;
bool is_sustaining = false;
int sustain_length = 4000;
int sustain_count = 0;
bool trigger_value = false;
bool last_trigger_value = false;
int last_led_value = 0;
int mynote=0;
bool trigger = false;
int numnotes;
int myscalenotes[7];
bool started = false;
int priority = 0;
int tapX = 0;
int tapactual;
int tap_time;
int time_actual;
int input1X = 0;
float BPM;
int max_BPM = 500;
int min_BPM = 10;
int max_time = ((1/(min_BPM/60)) * 1000);
int min_time = ((1/(max_BPM/60)) * 1000);
int c;
static const uint32_t DAC_CAL = 6826;
#define SAMPLE_T int16_t
#define ZERO 2047
#define BUF_SIZE 64 // 64
SAMPLE_T wav[BUF_SIZE];
#define MIN_WL 5
#define NOISE_L 24
size_t ks_wptr; // position in wavetable
SAMPLE_T ks_prev; // previous sample
size_t wl;
void updateCV(uint32_t DC_Value) {
dac60.setVoltage(DC_Value, false);
}
void ks_init(size_t wl) {
// initialize wavetable to short noise burst
size_t i;
for(i = 0; i < wl; i++) {
if(i < NOISE_L)
{ // short burst of noise
wav[i] = (SAMPLE_T)(rand() & 0x0FFF) - ZERO;
}
else
{
wav[i] = 0;
}
}
// initialize wavetable pointer
ks_wptr = 0;
// initialize filter
SAMPLE_T ks_prev = wav[wl-1];
}
SAMPLE_T ks_iter(size_t wl) {
// retrieve sample value from buffer
SAMPLE_T v = wav[ks_wptr];
// now filter the sample
wav[ks_wptr] = (ks_prev / 2) + (v / 2);
ks_prev = v;
// recur
ks_wptr = (ks_wptr + 1) % wl;
// return output sample
return v;
}
float smooth(float value_to_smooth){
total = total - readings[readIndex];
readings[readIndex] = value_to_smooth;
total = total + readings[readIndex];
readIndex = readIndex + 1;
if (readIndex >= NB_SMOOTHING) {
readIndex = 0;
}
average = total / NB_SMOOTHING;
return average;
}
float volt2freq(float volt){
return 440 / pow(2, 4.75) * pow(2, min(volt, OCT_RANGE) + BASE_OCTAVE); // 440/2^4.75 * 2^(min(volt e 10)+8)
}
float quantize(float volt){
return round(volt * 12) / 12.0; // perchè le mie note sono già calibrate
}
void change_scale(int myscale) //1C mag, , 2C min, 3 min mel, 4 7th, 5 jazz, 6 Maj Pentatonic, 7 Min Pentatonic
{
if (myscale==1)
{
numnotes=7;
myscalenotes[0]=0; // C3
myscalenotes[1]=150; // D3
myscalenotes[2]=310; // E3
myscalenotes[3]=390; // F3
myscalenotes[4]=560; // G3
myscalenotes[5]=720; // A3
myscalenotes[6]=890; // B3
myscalenotes[7]=965; // C4
}
else if (myscale==2)
{
numnotes=7;
......
}
else if (myscale==3)
{
numnotes=7;
.....
}
else if (myscale==4)
{
numnotes=7;
....
}
else if (myscale==5)
{
numnotes=6;
....
}
else if (myscale==6)
{
numnotes=5;
....
}
else if (myscale==7)
{
numnotes=5;
....
}
}
void input_pots()
{
if (internal_clock==1)
{
}
else if (internal_clock==2)
{
input_BMP = analogRead(CLOCK_BMP);
input_PERCENTAGE = analogRead(CLOCK_PERCENTAGE);
}
else if (internal_clock==3)
{
input_BMP=random(MIN_BPM,MAX_BPM);
input_PERCENTAGE = random(MIN_PERCENTAGE,MAX_PERCENTAGE);
}
}
void cycle_off()
{
trigger = false;
digitalWrite(CLOCK_LED, LOW);
}
void cycle_on() {
trigger = true;
digitalWrite(CLOCK_LED,HIGH);
input_pots();
BPM = map(input_BMP, 0, CALIBRATE_MAX_POT, MIN_BPM, MAX_BPM);
float duration_percentage = map(input_PERCENTAGE, 0, CALIBRATE_MAX_POT, 1, 90);
int cycletime = (60000/BPM);
float cycle_start = cycletime;
float cycle_stop = (cycletime * (duration_percentage/100));
timer.setTimeout(cycle_start, cycle_on);
timer.setTimeout(cycle_stop, cycle_off);
}
void setup() {
pinMode(CLOCK_LED, OUTPUT);
pinMode(TRIGGER_IN_PIN, INPUT);
pinMode(LOWER_IN_POT, INPUT);
pinMode(TUNE_IN_POT, INPUT);
pinMode(VOCT_IN_PIN,INPUT);
pinMode(CLOCK_LED,OUTPUT);
Serial.begin(9600);
dac60.begin(0x60);
change_scale(5);
old_myscale=5;
mynote=0;
input_BMP=random(MIN_BPM,MAX_BPM);
input_PERCENTAGE = random(MIN_PERCENTAGE,MAX_PERCENTAGE);
wl=1;
}
void loop() {
int pot_scale=analogRead(SCALE_IN_PIN);
int myscale = map(pot_scale, 0, CALIBRATE_MAX_POT, 1, 7);
if (myscale!=old_myscale)
{
change_scale(myscale);
old_myscale=myscale;
}
if (internal_clock==1)
{
trigger_value = digitalRead(TRIGGER_IN_PIN) == HIGH;
sustain_length = (4095.0 * analogRead(LOWER_IN_POT)/CALIBRATE_MAX_POT*KNOB_SCALE);
if (is_sustaining && sustain_count < sustain_length)
{
updateCV(ks_iter(wl) + ZERO); // ZERO=2047
sustain_count = (sustain_count + 1) % 100000; // 5%7=2 7%5=5
}
else
{
is_sustaining = false;
}
if (last_trigger_value == trigger_value)
{
if (trigger_value)
{
last_led_value -= 1;
if (last_led_value <= 0)
{
digitalWrite(CLOCK_LED, LOW);
}
}
return;
}
last_trigger_value = trigger_value;
if (!trigger_value)
{
last_led_value = 0;
digitalWrite(CLOCK_LED, LOW);
return;
}
}
else if (internal_clock==2)
{
if (!started)
{
cycle_on();
started = true;
}
timer.run();
time_actual=millis();
trigger_value = trigger;
sustain_length = (4095.0 * analogRead(LOWER_IN_POT)/CALIBRATE_MAX_POT*KNOB_SCALE);
if (is_sustaining && sustain_count < sustain_length)
{
updateCV(ks_iter(wl) + ZERO); // ZERO=2047
sustain_count = (sustain_count + 1) % 100000; // 5%7=2 7%5=5
}
else
{
is_sustaining = false;
}
if (last_trigger_value == trigger_value)
{
if (trigger_value)
{
last_led_value -= 1;
if (last_led_value <= 0)
{
digitalWrite(CLOCK_LED, LOW);
}
}
return;
}
last_trigger_value = trigger_value;
if (!trigger_value)
{
last_led_value = 0;
digitalWrite(CLOCK_LED, LOW);
return;
}
}
else if (internal_clock==3)
{
if (!started)
{
cycle_on();
started = true;
}
timer.run();
time_actual=millis();
trigger_value = trigger;
sustain_length = (4095.0 * analogRead(LOWER_IN_POT)/CALIBRATE_MAX_POT*KNOB_SCALE);
if (is_sustaining && sustain_count < sustain_length)
{
updateCV(ks_iter(wl) + ZERO); // ZERO=2047
sustain_count = (sustain_count + 1) % 100000; // 5%7=2 7%5=5
}
else
{
is_sustaining = false;
}
if (last_trigger_value == trigger_value)
{
if (trigger_value)
{
last_led_value -= 1;
if (last_led_value <= 0)
{
digitalWrite(CLOCK_LED, LOW);
}
}
return;
}
last_trigger_value = trigger_value;
if (!trigger_value)
{
last_led_value = 0;
digitalWrite(CLOCK_LED, LOW);
return;
}
}
if (usescale==1)
{
if (random_mysound==1)
{
mysound=random(0,numnotes);
}
else
{
mysound=map(analogRead(VOCT_IN_PIN),0,CALIBRATE_MAX_POT,0,numnotes);
}
if (mysound!=old_mysound)
{
if (mysound>numnotes)
{
mysound=0;
}
float myvolt=myscalenotes[mysound]/4096.0*5.0;
volt=(1.0*analogRead(TUNE_IN_POT)/CALIBRATE_MAX_POT*KNOB_SCALE)+(myvolt/204.0*VOCT_SCALE);
old_mysound=mysound;
}
}
else if (usescale==0)
{
volt = (1.0 * analogRead(TUNE_IN_POT)/CALIBRATE_MAX_POT*KNOB_SCALE) + (analogRead(VOCT_IN_PIN)/204.0*VOCT_SCALE);
}
else if (usescale==-1)
{
volt = (map(analogRead(TUNE_FROM_MCP4725),0,CALIBRATE_MAX_POT,0,5));
}
// 0.00 <-> 1.15 + 0.00 <-> 5.1 ==> 0.<->6.16
volt = smooth(volt);
volt = quantize(volt);
// silence
updateCV(ZERO); // SILENCE ZERO=2046
// choose wavelength
wl = (round(volt2freq(volt)) % (BUF_SIZE - MIN_WL)) + MIN_WL; // wl=(round() % (64-5))+5; wl=(round() % 59)+5
// initialize Karplus-Strong algorithm with this wavelength
ks_init(wl);
is_sustaining = true;
sustain_count = 0;
last_led_value = 30;
digitalWrite(CLOCK_LED, HIGH);
}