//************************************************** ***********************
// DIY Synth "Shruthi II" with Teensy 4.1 board and 16Bit Stereo DAC
//
// (c) Rolf Degen Version 1.02 15.10.2020
//************************************************** ***********************
#include <ST7735_t3.h>
#include <Audio.h>
#include <MIDI.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#define ENCODER_OPTIMIZE_INTERRUPTS
#include <Encoder.h>
#include <ResponsiveAnalogRead.h>
#define TFT_SCLK 27 // SCLK can also use pin 14
#define TFT_MOSI 26 // MOSI can also use pin 7
#define TFT_CS 25 // CS & DC can use pins 2, 6, 9, 10, 15, 20, 21, 22, 23
#define TFT_DC 24 // but certain pairs must NOT be used: 2+10, 6+9, 20+23, 21+22
#define TFT_RST 9 // RST can use any pin
#define RGB(r,g,b) (b<<11|g<<6|r)
#define ST7735_BLACK 0x0000
#define ST7735_GRAY 0x8410
#define ST7735_WHITE 0xFFFF
#define ST7735_RED 0xF800
#define ST7735_ORANGE 0xFA60
#define ST7735_YELLOW 0xFFE0
#define ST7735_LIME 0x07FF
#define ST7735_GREEN 0x07E0
#define ST7735_CYAN 0x07FF
#define ST7735_AQUA 0x04FF
#define ST7735_BLUE 0x001F
#define ST7735_MAGENTA 0xF81F
#define ST7735_PINK 0xF8FF
#define Menu_Osc 0 // Menu pages
#define Menu_AmpEnv 1
#define Menu_FilterEnv 2
#define Menu_Filter 3
#define LowPass 0
#define BandPass 1
#define HighPass 2
#define pi 3.14159
#define NO_OF_VOICES 6
//------------------------------------------------------
// Global var
//------------------------------------------------------
const int ANALOG_PIN8 = A8;
unsigned long previousTime_cpu = 0;
unsigned long previousTime_pot = 0;
unsigned long previousTime_midi = 0;
unsigned long previousTime_ADC = 0;
const int interval_cpu = 200; // poll interval CPU usage
const int interval_pot = 35; // poll interval pots and keys
const int interval_ADC = 15; // poll ADC
const int interval_midi = 1; // poll interval midi data
const uint8_t channel = 1;
uint8_t note = 0;
byte velocity = 0;
float freq = 0;
int pitch_bnd = 1;
float bendf = 0;
float BendFactor = 1;
int pot_1 = 0;
int pot_2 = 0;
int pot_3 = 0;
int pot_4 = 0;
int pot_1_old = 0;
int pot_2_old = 0;
int pot_3_old = 0;
int pot_4_old = 0;
uint8_t Amp_env_delay = 0;
uint8_t Amp_env_att = 20;
uint8_t Amp_env_hold = 0;
uint8_t Amp_env_dcy = 30;
uint8_t Amp_env_sus = 40;
uint8_t Amp_env_rel = 50;
uint8_t Filter_env_delay = 0;
uint8_t Filter_env_att = 80;
uint8_t Filter_env_hold = 0;
uint8_t Filter_env_dcy = 70;
uint8_t Filter_env_sus = 70;
uint8_t Filter_env_rel = 60;
uint8_t Filter_cut = 64;
uint8_t Filter_res = 20;
uint8_t Filter_key = 50;
uint8_t Filter_typ = 0;
boolean pot_1_change = false;
boolean pot_2_change = false;
boolean pot_3_change = false;
boolean pot_4_change = false;
uint8_t Menu_page = 0;
float pot_div127 = 0.228; // pot_value divider
int oldPosition = -999;
uint8_t Osc_waveform = 0;
struct VoiceAndNote {
int note;
long timeOn;
boolean voiceOn;
uint8_t lampTimeOn;
};
struct VoiceAndNote voices[NO_OF_VOICES] = {
{ -1, 0, false, 0},
{ -1, 0, false, 0},
{ -1, 0, false, 0},
{ -1, 0, false, 0},
{ -1, 0, false, 0},
{ -1, 0, false, 0}
};
int voiceToReturn = -1; // Voices allocation
long earliestTime = millis(); // Voices allocation
//************************************************** ***********************
// Tabels
//************************************************** ***********************
// Sine filter curv ------------------------------------------------------
const byte Filter_curve[385] PROGMEM = {
1, 2, 2, 3, 2, 3, 3, 4,
5, 4, 7, 5, 9, 7, 10, 11,
11, 13, 13, 17, 16, 18, 21, 21,
23, 25, 27, 28, 32, 31, 36, 36,
39, 41, 43, 46, 48, 51, 53, 55,
57, 62, 63, 65, 70, 70, 75, 76,
81, 82, 85, 89, 92, 94, 97, 100,
104, 107, 109, 112, 116, 119, 122, 124,
129, 130, 135, 137, 140, 144, 147, 148,
154, 155, 158, 163, 163, 169, 169, 174,
177, 178, 182, 185, 187, 191, 192, 195,
199, 200, 203, 205, 209, 210, 212, 216,
216, 220, 221, 223, 226, 227, 230, 230,
233, 235, 235, 239, 238, 241, 242, 243,
245, 245, 246, 249, 247, 251, 249, 252,
251, 252, 253, 253, 253, 254, 254, 254,
253, 255, 254, 253, 253, 254, 252, 253,
251, 251, 250, 250, 248, 248, 246, 246,
245, 242, 243, 240, 239, 238, 236, 234,
233, 231, 230, 226, 226, 224, 221, 219,
217, 215, 212, 211, 208, 206, 202, 201,
198, 196, 192, 190, 188, 184, 182, 179,
177, 173, 170, 168, 164, 162, 158, 156,
153, 149, 147, 143, 141, 136, 135, 131,
128, 125, 122, 118, 116, 113, 109, 106,
104, 101, 96, 95, 92, 88, 85, 83,
80, 77, 74, 71, 69, 66, 63, 61,
57, 56, 53, 50, 49, 45, 43, 42,
38, 37, 35, 32, 31, 29, 26, 26,
22, 22, 20, 19, 16, 16, 13, 14,
11, 10, 10, 8, 8, 6, 6, 5,
4, 5, 2, 3, 2, 2, 2, 3,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0,
};
// Potentiometer Power table
const int Pot_PowerTab[128] PROGMEM = {
0, 0, 1, 2, 3, 4, 5, 6,
7, 9, 12, 15, 19, 24, 29, 36,
43, 50, 59, 68, 78, 89, 101, 114,
128, 143, 159, 176, 194, 214, 234, 256,
279, 303, 329, 355, 384, 413, 444, 476,
510, 545, 582, 620, 660, 701, 744, 789,
835, 882, 932, 983, 1036, 1091, 1147, 1206,
1266, 1328, 1392, 1457, 1525, 1595, 1666, 1740,
1815, 1893, 1973, 2055, 2138, 2224, 2313, 2403,
2495, 2590, 2687, 2786, 2888, 2991, 3097, 3206,
3317, 3430, 3545, 3663, 3784, 3907, 4032, 4160,
4290, 4423, 4559, 4697, 4837, 4981, 5126, 5275,
5426, 5580, 5737, 5896, 6059, 6224, 6391, 6562,
6736, 6912, 7091, 7273, 7458, 7646, 7837, 8031,
8228, 8428, 8630, 8836, 9045, 9257, 9473, 9691,
9912, 10137, 10365, 10596, 10830, 11068, 11800, 11800,
};
// Filter Frequency
/*
// DeepMind 6
const int FilterFrequency[256] PROGMEM = {
50, 51, 52, 54, 55, 56, 58, 59,
60, 62, 63, 65, 66, 68, 69, 71,
73, 75, 76, 78, 80, 82, 84, 86,
88, 90, 92, 94, 97, 99, 101, 104,
106, 109, 111, 114, 116, 119, 122, 125,
128, 131, 134, 137, 141, 144, 147, 151,
154, 158, 162, 166, 170, 174, 178, 182,
186, 191, 195, 200, 205, 210, 215, 220,
225, 230, 236, 241, 247, 253, 259, 265,
271, 278, 284, 291, 298, 305, 313, 320,
328, 335, 343, 351, 360, 368, 377, 386,
395, 405, 414, 424, 434, 445, 455, 466,
477, 488, 500, 512, 524, 537, 549, 562,
576, 589, 603, 618, 632, 647, 663, 679,
695, 711, 728, 746, 763, 781, 800, 819,
838, 858, 879, 900, 921, 943, 965, 988,
1012, 1036, 1060, 1086, 1112, 1138, 1165, 1193,
1221, 1250, 1280, 1310, 1341, 1373, 1406, 1439,
1474, 1509, 1544, 1581, 1619, 1657, 1697, 1737,
};
*/
// TSynth
const static int FilterFrequency[256] = {
20, 20, 22, 23, 24, 26, 27, 28,
29, 31, 32, 33, 34, 35, 36, 38,
39, 40, 41, 43, 44, 46, 47, 49,
50, 52, 53, 55, 57, 59, 61, 63,
65, 68, 70, 73, 76, 78, 81, 84,
87, 91, 94, 98, 102, 106, 110, 114,
119, 123, 128, 133, 138, 144, 149, 155,
161, 167, 174, 181, 187, 195, 202, 210,
218, 226, 234, 243, 252, 261, 271, 281,
291, 301, 312, 323, 334, 346, 358, 370,
383, 395, 409, 422, 436, 451, 465, 480,
496, 512, 528, 544, 561, 578, 596, 614,
633, 652, 671, 691, 711, 732, 753, 774,
796, 818, 841, 865, 888, 913, 937, 962,
988, 1014, 1041, 1068, 1096, 1124, 1152, 1182,
1211, 1242, 1272, 1304, 1335, 1368, 1401, 1434,
1468, 1503, 1538, 1574, 1610, 1647, 1684, 1722,
1761, 1800, 1840, 1881, 1922, 1964, 2006, 2049,
2093, 2137, 2182, 2227, 2274, 2320, 2368, 2416,
2465, 2515, 2565, 2616, 2668, 2720, 2773, 2827,
2881, 2936, 2992, 3049, 3106, 3164, 3223, 3283,
3343, 3404, 3466, 3529, 3592, 3656, 3721, 3787,
3853, 3921, 3989, 4058, 4127, 4198, 4269, 4341,
4414, 4488, 4563, 4638, 4715, 4792, 4870, 4949,
5029, 5109, 5191, 5273, 5357, 5441, 5526, 5612,
5699, 5787, 5876, 5965, 6056, 6147, 6240, 6333,
6427, 6523, 6619, 6716, 6814, 6913, 7013, 7114,
7216, 7319, 7424, 7529, 7635, 7742, 7850, 7959,
8069, 8180, 8292, 8405, 8519, 8634, 8751, 8868,
8986, 9106, 9226, 9348, 9471, 9594, 9719, 9845,
9972, 10100, 10230, 10360, 10491, 10624, 10758, 10893,
11029, 11166, 11304, 11443, 11584, 11726, 12000, 12000
};
// Waveform text
const char* const Waveform_text[] PROGMEM = {"SINE","SAW ","SQU ","TRI ","VTRI","ARB ","PULS","S&H "};
//------------------------------------------------------
// GUItool
//------------------------------------------------------
ST7735_t3 disp = ST7735_t3(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
Encoder myEnc(31, 30);
ResponsiveAnalogRead analog1(A0, true);
ResponsiveAnalogRead analog2(A2, true);
ResponsiveAnalogRead analog3(A3, true);
ResponsiveAnalogRead analog4(A8, true);
// GUItool: begin automatically generated code
AudioSynthWaveformDc dc1; //xy=393,162
AudioSynthWaveformDc dc2; //xy=387,383
AudioSynthWaveformDc dc3; //xy=385,590
AudioSynthWaveformDc dc4; //xy=382,789
AudioSynthWaveformDc dc5; //xy=380,959
AudioSynthWaveformDc dc6; //xy=376,1152
AudioSynthWaveform waveform1; //xy=399,92
AudioSynthWaveform waveform2; //xy=395,317
AudioSynthWaveform waveform3; //xy=394,528
AudioSynthWaveform waveform4; //xy=393,735
AudioSynthWaveform waveform5; //xy=389,909
AudioSynthWaveform waveform6; //xy=387,1093
AudioEffectEnvelope envelope1_0; //xy=1101,105
AudioEffectEnvelope envelope2_0; //xy=1104,331
AudioEffectEnvelope envelope3_0; //xy=1104,539
AudioEffectEnvelope envelope4_0; //xy=1106,745
AudioEffectEnvelope envelope5_0; //xy=1108,923
AudioEffectEnvelope envelope6_0; //xy=1110,1105
AudioEffectEnvelope envelope1_1; //xy=559,162
AudioEffectEnvelope envelope2_1; //xy=548,382
AudioEffectEnvelope envelope3_1; //xy=539,590
AudioEffectEnvelope envelope4_1; //xy=538,789
AudioEffectEnvelope envelope5_1; //xy=536,959
AudioEffectEnvelope envelope6_1; //xy=537,1152
AudioFilterStateVariable filter1; //xy=723,99
AudioFilterStateVariable filter2; //xy=718,325
AudioFilterStateVariable filter3; //xy=712,533
AudioFilterStateVariable filter4; //xy=709,739
AudioFilterStateVariable filter5; //xy=711,917
AudioFilterStateVariable filter6; //xy=713,1100
AudioMixer4 mixer1; //xy=936,105
AudioMixer4 mixer2; //xy=931,331
AudioMixer4 mixer3; //xy=930,539
AudioMixer4 mixer4; //xy=931,745
AudioMixer4 mixer5; //xy=931,923
AudioMixer4 mixer6; //xy=929,1106
AudioMixer4 mixer20; //xy=1351,498
AudioMixer4 mixer21; //xy=1351,942
AudioMixer4 mixer22; //xy=1560,730
AudioOutputI2S i2s1; //xy=1745,728
AudioConnection patchCord1(dc6, envelope6_1);
AudioConnection patchCord2(dc5, envelope5_1);
AudioConnection patchCord3(dc4, envelope4_1);
AudioConnection patchCord4(dc3, envelope3_1);
AudioConnection patchCord5(dc2, envelope2_1);
AudioConnection patchCord6(waveform6, 0, filter6, 0);
AudioConnection patchCord7(waveform5, 0, filter5, 0);
AudioConnection patchCord8(dc1, envelope1_1);
AudioConnection patchCord9(waveform4, 0, filter4, 0);
AudioConnection patchCord10(waveform3, 0, filter3, 0);
AudioConnection patchCord11(waveform2, 0, filter2, 0);
AudioConnection patchCord12(waveform1, 0, filter1, 0);
AudioConnection patchCord13(envelope5_1, 0, filter5, 1);
AudioConnection patchCord14(envelope4_1, 0, filter4, 1);
AudioConnection patchCord15(envelope3_1, 0, filter3, 1);
AudioConnection patchCord16(envelope6_1, 0, filter6, 1);
AudioConnection patchCord17(envelope2_1, 0, filter2, 1);
AudioConnection patchCord18(envelope1_1, 0, filter1, 1);
AudioConnection patchCord19(filter4, 0, mixer4, 0);
AudioConnection patchCord20(filter4, 1, mixer4, 1);
AudioConnection patchCord21(filter4, 2, mixer4, 2);
AudioConnection patchCord22(filter3, 0, mixer3, 0);
AudioConnection patchCord23(filter3, 1, mixer3, 1);
AudioConnection patchCord24(filter3, 2, mixer3, 2);
AudioConnection patchCord25(filter5, 0, mixer5, 0);
AudioConnection patchCord26(filter5, 1, mixer5, 1);
AudioConnection patchCord27(filter5, 2, mixer5, 2);
AudioConnection patchCord28(filter6, 0, mixer6, 0);
AudioConnection patchCord29(filter6, 1, mixer6, 1);
AudioConnection patchCord30(filter6, 2, mixer6, 2);
AudioConnection patchCord31(filter2, 0, mixer2, 0);
AudioConnection patchCord32(filter2, 1, mixer2, 1);
AudioConnection patchCord33(filter2, 2, mixer2, 2);
AudioConnection patchCord34(filter1, 0, mixer1, 0);
AudioConnection patchCord35(filter1, 1, mixer1, 1);
AudioConnection patchCord36(filter1, 2, mixer1, 2);
AudioConnection patchCord37(mixer3, envelope3_0);
AudioConnection patchCord38(mixer2, envelope2_0);
AudioConnection patchCord39(mixer6, envelope6_0);
AudioConnection patchCord40(mixer4, envelope4_0);
AudioConnection patchCord41(mixer5, envelope5_0);
AudioConnection patchCord42(mixer1, envelope1_0);
AudioConnection patchCord43(envelope1_0, 0, mixer20, 0);
AudioConnection patchCord44(envelope2_0, 0, mixer20, 1);
AudioConnection patchCord45(envelope3_0, 0, mixer20, 2);
AudioConnection patchCord46(envelope4_0, 0, mixer20, 3);
AudioConnection patchCord47(envelope5_0, 0, mixer21, 0);
AudioConnection patchCord48(envelope6_0, 0, mixer21, 1);
AudioConnection patchCord49(mixer20, 0, mixer22, 0);
AudioConnection patchCord50(mixer21, 0, mixer22, 1);
AudioConnection patchCord51(mixer22, 0, i2s1, 0);
AudioConnection patchCord52(mixer22, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1; //xy=1735,625
// GUItool: end automatically generated code
//************************************************** ***********************
// draw Voice Lamps
//************************************************** ***********************
void draw_Voice_Lamps(void)
{
disp.drawLine(128, 1, 128, 16, ST7735_GRAY);
disp.drawRect(133, 3, 7, 4, ST7735_RED);
disp.drawRect(133 + 10, 3, 7, 4, ST7735_RED);
disp.drawRect(133 + 10 + 10, 3, 7, 4, ST7735_RED);
disp.drawRect(133, 11, 7, 4, ST7735_RED);
disp.drawRect(133 + 10, 11, 7, 4, ST7735_RED);
disp.drawRect(133 + 10 + 10, 11, 7, 4, ST7735_RED);
}
//************************************************** ***********************
// Oscillator menu
//************************************************** ***********************
void Osc_menu (void)
{
disp.fillScreen(ST7735_BLACK);
disp.drawLine(0, 20, 240, 20, ST7735_YELLOW);
disp.setCursor(10, 5);
disp.setTextSize(0);
disp.print("OSC");
disp.setTextColor(ST7735_WHITE);
disp.setCursor(10, 105);
disp.print("SHA");
disp.setCursor(10 + 40, 105);
disp.print("PRM");
disp.setCursor(10 + 40 + 40, 105);
disp.print("RNG");
disp.setCursor(10 + 40 + 40 + 40, 105);
disp.print("TUN");
// draw pot values --------------------------
disp.drawLine(4,116,30,116,ST7735_BLUE);
disp.drawLine(4+40,116,30+40,116,ST7735_BLUE);
disp.drawLine(4+40+40,116,30+40+40,116,ST7735_BLUE );
disp.drawLine(4+40+40+40,116,30+40+40+40,116,ST773 5_BLUE);
// draw voice lamps --------------------------
draw_Voice_Lamps();
//draw_AMP_envLine();
//pot_1 = Amp_env_att;
//pot_2 = Amp_env_dcy;
//pot_3 = Amp_env_sus;
//pot_4 = Amp_env_rel;
pot_1_change = true;
pot_2_change = true;
pot_3_change = true;
pot_4_change = true;
//set_AMP_envelope();
refresh_pot_values();
}
//************************************************** ***********************
// AMP envelope menu
//************************************************** ***********************
void AMP_envelope_menu (void)
{
disp.fillScreen(ST7735_BLACK);
disp.drawLine(0, 20, 240, 20, ST7735_YELLOW);
disp.setCursor(10, 5);
disp.setTextSize(0);
disp.print("AMP ENV");
disp.setTextColor(ST7735_WHITE);
disp.setCursor(10, 105);
disp.print("ATK");
disp.setCursor(10 + 40, 105);
disp.print("DCY");
disp.setCursor(10 + 40 + 40, 105);
disp.print("SUS");
disp.setCursor(10 + 40 + 40 + 40, 105);
disp.print("REL");
// draw pot values --------------------------
disp.drawLine(4,116,30,116,ST7735_BLUE);
disp.drawLine(4+40,116,30+40,116,ST7735_BLUE);
disp.drawLine(4+40+40,116,30+40+40,116,ST7735_BLUE );
disp.drawLine(4+40+40+40,116,30+40+40+40,116,ST773 5_BLUE);
// draw voice lamps --------------------------
draw_Voice_Lamps();
draw_AMP_envLine();
pot_1 = Amp_env_att;
pot_2 = Amp_env_dcy;
pot_3 = Amp_env_sus;
pot_4 = Amp_env_rel;
pot_1_change = true;
pot_2_change = true;
pot_3_change = true;
pot_4_change = true;
set_AMP_envelope();
refresh_pot_values();
}
//************************************************** ***********************
// FILTER envelope menu
//************************************************** ***********************
void Filter_envelope_menu (void)
{
disp.fillScreen(ST7735_BLACK);
disp.drawLine(0, 20, 240, 20, ST7735_YELLOW);
disp.setCursor(10, 5);
disp.setTextSize(0);
disp.print("FILTER ENV");
disp.setTextColor(ST7735_WHITE);
disp.setCursor(10, 105);
disp.print("ATK");
disp.setCursor(10 + 40, 105);
disp.print("DCY");
disp.setCursor(10 + 40 + 40, 105);
disp.print("SUS");
disp.setCursor(10 + 40 + 40 + 40, 105);
disp.print("REL");
// draw pot values --------------------------
disp.drawLine(4,116,30,116,ST7735_BLUE);
disp.drawLine(4+40,116,30+40,116,ST7735_BLUE);
disp.drawLine(4+40+40,116,30+40+40,116,ST7735_BLUE );
disp.drawLine(4+40+40+40,116,30+40+40+40,116,ST773 5_BLUE);
// draw voice lamps --------------------------
draw_Voice_Lamps();
draw_Filter_envLine();
pot_1 = Filter_env_att;
pot_2 = Filter_env_dcy;
pot_3 = Filter_env_sus;
pot_4 = Filter_env_rel;
pot_1_change = true;
pot_2_change = true;
pot_3_change = true;
pot_4_change = true;
set_Filter_envelope();
refresh_pot_values();
}
//************************************************** ***********************
// FILTER menu
//************************************************** ***********************
void Filter_menu (void)
{
disp.fillScreen(ST7735_BLACK);
disp.drawLine(0, 20, 240, 20, ST7735_YELLOW);
disp.setCursor(10, 5);
disp.setTextSize(0);
disp.print("FILTER");
disp.setTextColor(ST7735_WHITE);
disp.setCursor(10, 105);
disp.print("FRQ");
disp.setCursor(10 + 40, 105);
disp.print("RES");
disp.setCursor(10 + 40 + 40, 105);
disp.print("KEY");
disp.setCursor(6 + 40 + 40 + 40+4, 105);
disp.print("MOD");
// draw pot values --------------------------
disp.drawLine(4,116,30,116,ST7735_BLUE);
disp.drawLine(4+40,116,30+40,116,ST7735_BLUE);
disp.drawLine(4+40+40,116,30+40+40,116,ST7735_BLUE );
disp.drawLine(4+40+40+40,116,30+40+40+40,116,ST773 5_BLUE);
// draw voice lamps --------------------------
draw_Voice_Lamps();
// draw diagramm line
disp.drawLine(19,45,19,45+41,ST7735_GRAY);
disp.drawLine(19,45+41,19+115,45+41,ST7735_GRAY);
disp.setTextColor(ST7735_GRAY);
disp.setCursor(7, 46);
disp.print("dB");
disp.setCursor(110, 88);
disp.print("f/Hz");
draw_filter_curves(Filter_typ);
pot_1 = Filter_cut;
pot_2 = Filter_res;
pot_3 = Filter_key;
pot_4 = Filter_typ * 42; // pot_4 value
set_Filter_typ();
pot_1_change = true;
pot_2_change = true;
pot_3_change = true;
pot_4_change = true;
set_Filter_values();
refresh_pot_values();
}
//************************************************** ***********************
// draw_DCA envelope line
//************************************************** ***********************
void draw_AMP_envLine(void)
{
uint8_t xplot1 = Amp_env_att;
uint8_t xplot1_decay = Amp_env_dcy;
uint8_t yplot2_sustain = Amp_env_sus;
uint8_t xplot3_release = Amp_env_rel;
static uint8_t xplot1_temp = 10;
static uint8_t yplot2_sustain_temp = 40;
static uint8_t xplot1_decay_temp = 0;
static uint8_t xplot3_release_temp = 0;
// Attack line
disp.drawLine(10,85,xplot1_temp,40,ST7735_BLACK); // delete old line
xplot1 = 10+(Amp_env_att / 4);
disp.drawLine(10,85,xplot1,40,ST7735_RED); // draw new line
// Decay Line
xplot1_decay = (Amp_env_dcy / 4);
yplot2_sustain = 85 - ((Amp_env_sus * 85)/239);
disp.drawLine(xplot1_temp,40,xplot1_temp + xplot1_decay_temp,yplot2_sustain_temp,ST7735_BLACK );
disp.drawLine(xplot1,40,xplot1 + xplot1_decay,yplot2_sustain,ST7735_RED);
// Sustain Line
disp.drawLine(xplot1_temp + xplot1_decay_temp,yplot2_sustain_temp,90,yplot2_su stain_temp,ST7735_BLACK);
disp.drawLine(xplot1 + xplot1_decay,yplot2_sustain,90,yplot2_sustain,ST77 35_RED);
// Relaese line
xplot3_release = (90 + ((Amp_env_rel * 25)/127));
disp.drawLine(90,yplot2_sustain_temp,xplot3_releas e_temp,85,ST7735_BLACK);
disp.drawLine(90,yplot2_sustain,xplot3_release,85, ST7735_RED);
// draw little rectangle for ADSR points
disp.fillRect(xplot1_temp - 2,39,5,5,ST7735_BLACK);
disp.fillRect(xplot1 - 2,39,5,5,ST7735_BLUE);
disp.fillRect(xplot1_temp + xplot1_decay_temp -2,yplot2_sustain_temp-1,5,5,ST7735_BLACK);
disp.fillRect(xplot1 + xplot1_decay -2,yplot2_sustain-1,5,5,ST7735_BLUE);
disp.fillRect(88,yplot2_sustain_temp-1,5,5,ST7735_BLACK);
disp.fillRect(88,yplot2_sustain-1,5,5,ST7735_BLUE);
// draw vertikal point-line for relaese
for (uint8_t i = 40; i <= 85; i++){
disp.drawPixel(90,i,ST7735_GRAY);
i++;
i++;
}
// save current lines for delete old lines
xplot1_temp = xplot1;
yplot2_sustain_temp = yplot2_sustain;
xplot1_decay_temp = xplot1_decay;
xplot3_release_temp = xplot3_release;
}
//################################################## #######################
// draw Filter envelope line
//################################################## #######################
void draw_Filter_envLine (void)
{
uint8_t xplot1 = Filter_env_att;
uint8_t yplot2_sustain = Filter_env_sus;
uint8_t xplot1_decay = Filter_env_dcy;
uint8_t xplot3_release = Filter_env_rel;
static uint8_t xplot1_temp = 10;
static uint8_t yplot2_sustain_temp = 40;
static uint8_t xplot1_decay_temp = 0;
static uint8_t xplot3_release_temp = 0;
// Attack line
disp.drawLine(10,85,xplot1_temp,40,ST7735_BLACK); // delete old line
xplot1 = 10+(Filter_env_att / 4);
disp.drawLine(10,85,xplot1,40,ST7735_RED); // draw new line
// Decay Line
xplot1_decay = (Filter_env_dcy / 4);
yplot2_sustain = 85 - ((Filter_env_sus * 85)/239);
disp.drawLine(xplot1_temp,40,xplot1_temp + xplot1_decay_temp,yplot2_sustain_temp,ST7735_BLACK );
disp.drawLine(xplot1,40,xplot1 + xplot1_decay,yplot2_sustain,ST7735_RED);
// Sustain Line
disp.drawLine(xplot1_temp + xplot1_decay_temp,yplot2_sustain_temp,90,yplot2_su stain_temp,ST7735_BLACK);
disp.drawLine(xplot1 + xplot1_decay,yplot2_sustain,90,yplot2_sustain,ST77 35_RED);
// Relaese line
xplot3_release = (90 + ((Filter_env_rel * 25)/127));
disp.drawLine(90,yplot2_sustain_temp,xplot3_releas e_temp,85,ST7735_BLACK);
disp.drawLine(90,yplot2_sustain,xplot3_release,85, ST7735_RED);
// draw little rectangle for ADSR points
disp.fillRect(xplot1_temp - 2,39,5,5,ST7735_BLACK);
disp.fillRect(xplot1 - 2,39,5,5,ST7735_BLUE);
disp.fillRect(xplot1_temp + xplot1_decay_temp -2,yplot2_sustain_temp-1,5,5,ST7735_BLACK);
disp.fillRect(xplot1 + xplot1_decay -2,yplot2_sustain-1,5,5,ST7735_BLUE);
disp.fillRect(88,yplot2_sustain_temp-1,5,5,ST7735_BLACK);
disp.fillRect(88,yplot2_sustain-1,5,5,ST7735_BLUE);
// draw vertikal point-line for relaese
for (uint8_t i = 40; i <= 85; i++){
disp.drawPixel(90,i,ST7735_GRAY);
i++;
i++;
}
// save current lines for delete old lines
xplot1_temp = xplot1;
yplot2_sustain_temp = yplot2_sustain;
xplot1_decay_temp = xplot1_decay;
xplot3_release_temp = xplot3_release;
}
//************************************************** ***********************
// draw Filter curves on LCD
//************************************************** ***********************
void draw_filter_curves (uint8_t filterTyp)
{
// clear old curve
disp.fillRect(20,48,114,38,ST7735_BLACK);
// draw LowPass Filter curve -----------------------------------------
if (filterTyp == LowPass){
const uint8_t x_plot = 68;
const uint8_t y_plot = 85;
uint8_t pot_1_cut = Filter_cut;
uint8_t pot_2_res = Filter_res;
uint8_t x = 40;
uint16_t r = 0;
uint8_t y = 0;
uint8_t y_ = 0;
uint8_t i = 0;
uint8_t i_ = 0;
uint8_t q_typ = 12; // Filter Q
uint16_t resonance = 0;
for (i = 0; i < 48; i++)
{
resonance = (Filter_curve[(i * 8)]);
resonance = (((resonance >> 2) * pot_2_res) >> 7);
r = (x + r - y) + resonance;
y = r / q_typ;
disp.drawLine((pot_1_cut / 2) + x_plot - i_,(y_plot - y_ / 2), (pot_1_cut / 2) + x_plot - i, (y_plot - y / 2),ST7735_RED);
i_ = i;
y_ = y;
}
disp.drawLine(20, (y_plot - y_ / 2), 20 + (pot_1_cut / 2), (y_plot - y_ / 2), ST7735_RED);
}
// draw BandPass Filter curve ----------------------------------------
else if (filterTyp == BandPass){
const uint8_t x_plot = 20;
const uint8_t y_plot = 85;
uint8_t pot_1_cut = Filter_cut;
uint8_t pot_2_res = Filter_res;
uint8_t x = 40;
uint16_t r = 0;
uint8_t y = 0;
uint8_t y_ = 0;
uint8_t i = 0;
uint8_t i_ = 0;
uint8_t q_typ = 12; // Filter Q
uint16_t resonance = 0;
for (i = 0; i < 27; i++)
{
resonance = (Filter_curve[(i * 8)]);
resonance = (((resonance >> 2) * pot_2_res) >> 7);
r = (x + r - y) + resonance;
y = r / q_typ;
disp.drawLine((pot_1_cut / 2) + x_plot + i_,(y_plot - y_ / 2),(pot_1_cut / 2) + x_plot + i,(y_plot - y_ / 2),ST7735_RED);
disp.drawLine((pot_1_cut / 2) + x_plot + 49 - i_,(y_plot - y_ / 2),(pot_1_cut / 2) + x_plot + 49 - i,(y_plot - y_ / 2),ST7735_RED);
i_ = i;
y_ = y;
}
}
// draw HighPass Filter curve ----------------------------------------
else if (filterTyp == HighPass){
const uint8_t x_plot = 20;
const uint8_t y_plot = 85;
uint8_t pot_1_cut = Filter_cut;
uint8_t pot_2_res = Filter_res;
uint8_t x = 40;
uint16_t r = 0;
uint8_t y = 0;
uint8_t y_ = 0;
uint8_t i = 0;
uint8_t i_ = 0;
uint8_t q_typ = 12; // Filter Q
uint16_t resonance = 0;
for (i = 0; i < 48; i++)
{
resonance = (Filter_curve[(i * 8)]);
resonance = (((resonance >> 2) * pot_2_res) >> 7);
r = (x + r - y) + resonance;
y = r / q_typ;
disp.drawLine((pot_1_cut / 2) + x_plot + i_,(y_plot - y_ / 2), (pot_1_cut / 2) + x_plot + i, (y_plot - y / 2),ST7735_RED);
i_ = i;
y_ = y;
}
disp.drawLine(68 + (pot_1 / 2), (y_plot - y_ / 2), 131, (y_plot - y_ / 2), ST7735_RED);
}
}
//################################################## #######################
// set Filter typ
//################################################## #######################
void set_Filter_typ(void)
{
if (pot_4 <= 39) // set LowPass
{
mixer1.gain(0, 1.0); // LP
mixer1.gain(1, 0); // BP
mixer1.gain(2, 0); // HP
mixer1.gain(3, 0); // --
mixer2.gain(0, 1.0); // LP
mixer2.gain(1, 0); // BP
mixer2.gain(2, 0); // HP
mixer2.gain(3, 0); // --
mixer3.gain(0, 1.0); // LP
mixer3.gain(1, 0); // BP
mixer3.gain(2, 0); // HP
mixer3.gain(3, 0); // --
mixer4.gain(0, 1.0); // LP
mixer4.gain(1, 0); // BP
mixer4.gain(2, 0); // HP
mixer4.gain(3, 0); // --
mixer5.gain(0, 1.0); // LP
mixer5.gain(1, 0); // BP
mixer5.gain(2, 0); // HP
mixer5.gain(3, 0); // --
mixer6.gain(0, 1.0); // LP
mixer6.gain(1, 0); // BP
mixer6.gain(2, 0); // HP
mixer6.gain(3, 0); // --
disp.fillRect(134, 120, 17, 8, ST7735_BLACK);
disp.setTextColor(ST7735_GRAY);
disp.setCursor(134, 120);
disp.print("LP");
Filter_typ = LowPass;
}
else if (pot_4 >= 42 && pot_4 <= 79) // set BandPass
{
mixer1.gain(0, 0); // LP
mixer1.gain(1, 2.0); // BP
mixer1.gain(2, 0); // HP
mixer1.gain(3, 0); // --
mixer2.gain(0, 0); // LP
mixer2.gain(1, 2.0); // BP
mixer2.gain(2, 0); // HP
mixer2.gain(3, 0); // --
mixer3.gain(0, 0); // LP
mixer3.gain(1, 2.0); // BP
mixer3.gain(2, 0); // HP
mixer3.gain(3, 0); // --
mixer4.gain(0, 0); // LP
mixer4.gain(1, 2.0); // BP
mixer4.gain(2, 0); // HP
mixer4.gain(3, 0); // --
mixer5.gain(0, 0); // LP
mixer5.gain(1, 2.0); // BP
mixer5.gain(2, 0); // HP
mixer5.gain(3, 0); // --
mixer6.gain(0, 0); // LP
mixer6.gain(1, 2.0); // BP
mixer6.gain(2, 0); // HP
mixer6.gain(3, 0); // --
disp.fillRect(134, 120, 17, 8, ST7735_BLACK);
disp.setTextColor(ST7735_GRAY);
disp.setCursor(134, 120);
disp.print("BP");
Filter_typ = BandPass;
}
else if (pot_4 >= 84 && pot_4 <= 127) // set HighPass
{
mixer1.gain(0, 0); // LP
mixer1.gain(1, 0); // BP
mixer1.gain(2, 2.0); // HP
mixer1.gain(3, 0); // --
mixer2.gain(0, 0); // LP
mixer2.gain(1, 0); // BP
mixer2.gain(2, 2.0); // HP
mixer2.gain(3, 0); // --
mixer3.gain(0, 0); // LP
mixer3.gain(1, 0); // BP
mixer3.gain(2, 2.0); // HP
mixer3.gain(3, 0); // --
mixer4.gain(0, 0); // LP
mixer4.gain(1, 0); // BP
mixer4.gain(2, 2.0); // HP
mixer4.gain(3, 0); // --
mixer5.gain(0, 0); // LP
mixer5.gain(1, 0); // BP
mixer5.gain(2, 2.0); // HP
mixer5.gain(3, 0); // --
mixer6.gain(0, 0); // LP
mixer6.gain(1, 0); // BP
mixer6.gain(2, 2.0); // HP
mixer6.gain(3, 0); // --
disp.fillRect(134, 120, 17, 8, ST7735_BLACK);
disp.setTextColor(ST7735_GRAY);
disp.setCursor(134, 120);
disp.print("HP");
Filter_typ = HighPass;
}
}
//################################################## #######################
// print CPU usage every 200ms
//################################################## #######################
void print_CPU_usage (void)
{
disp.fillRect(133, 25, 23, 8, ST7735_BLACK);
disp.setCursor(133, 26);
disp.setTextColor(ST7735_WHITE);
disp.print(AudioProcessorUsage());
}
//************************************************** ***********************
// read Potentiometers with averaging calculation
//************************************************** ***********************
boolean read_pots (void)
{
boolean pot_change = false;
int adc_sum = 0;
// read Potentiometer 1
for (uint8_t i = 0; i < 16; i++){
//analog1.update(); // averaging calculation
adc_sum = adc_sum + ((analog1.getValue()) >> 3);
}
pot_1 = adc_sum / 16;
if(pot_1_old != pot_1){
pot_1_old = pot_1;
pot_1_change = true;
pot_change = true;
}
// read Potentiometer 2
adc_sum = 0;
for (uint8_t i = 0; i < 16; i++){
//analog2.update();
adc_sum = adc_sum + ((analog2.getValue()) >> 3);
}
pot_2 = adc_sum / 16;
if(pot_2_old != pot_2){
pot_2_old = pot_2;
pot_2_change = true;
pot_change = true;
}
// read Potentiometer 3
adc_sum = 0;
for (uint8_t i = 0; i < 16; i++){
//analog3.update();
adc_sum = adc_sum + ((analog3.getValue()) >> 3);
}
pot_3 = adc_sum / 16;
if(pot_3_old != pot_3){
pot_3_old = pot_3;
pot_3_change = true;
pot_change = true;
}
// read Potentiometer 4
adc_sum = 0;
for (uint8_t i = 0; i < 16; i++){
//analog4.update();
adc_sum = adc_sum + ((analog4.getValue()) >> 3);
}
pot_4 = adc_sum / 16;
if(pot_4_old != pot_4){
pot_4_old = pot_4;
pot_4_change = true;
pot_change = true;
}
boolean temp_flag = pot_change;
pot_change = false;
return temp_flag;
}
//************************************************** ***********************
// draw Potentiometer values
//************************************************** ***********************
void refresh_pot_values(void)
{
uint8_t pot1_value = 0;
uint8_t pot2_value = 0;
uint8_t pot3_value = 0;
uint8_t pot4_value = 0;
if (pot_1_change == true)
{
pot1_value = pot_1;
disp.fillRect(4, 114, 32, 4, ST7735_BLACK);
disp.drawLine(4,116,32,116,ST7735_BLUE);
disp.drawLine(4 + (pot_div127 * pot1_value),114,4 + (pot_div127 * pot1_value),117,ST7735_RED);
pot_1_change = false;
}
if (pot_2_change == true)
{
pot2_value = pot_2;
disp.fillRect(4+40, 114, 32, 4, ST7735_BLACK);
disp.drawLine(4+40,116,32+40,116,ST7735_BLUE);
disp.drawLine(4 + 40 + (pot_div127 * pot2_value),114,4 + 40 + (pot_div127 * pot2_value),117,ST7735_RED);
pot_2_change = false;
}
if (pot_3_change == true)
{
pot3_value = pot_3;
disp.fillRect(4+40+40, 114, 32, 4, ST7735_BLACK);
disp.drawLine(4+40+40,116,32+40+40,116,ST7735_BLUE );
disp.drawLine(4 + 40 + 40+(pot_div127 * pot3_value),114,4 + 40 + 40+(pot_div127 * pot3_value),117,ST7735_RED);
pot_3_change = false;
}
if (pot_4_change == true)
{
pot4_value = pot_4;
disp.fillRect(4+40+40+40, 114, 32, 4, ST7735_BLACK);
disp.drawLine(4+40+40+40,116,32+40+40+40,116,ST773 5_BLUE);
disp.drawLine(4 + 40+40+40+(pot_div127 * pot4_value),114,4 + 40+40+40+(pot_div127 * pot4_value),117,ST7735_RED);
pot_4_change = false;
}
}
//************************************************** ***********************
// read Encoder
//************************************************** ***********************
boolean read_Encoder (void)
{
int newPosition = (myEnc.read() >> 2);
if (newPosition != oldPosition) {
if (newPosition < 0) {
newPosition = 0;
oldPosition = 0;
myEnc.write(0);
}
else if (newPosition > 9){
newPosition = 9;
oldPosition = 9;
myEnc.write(9 * 4);
}
oldPosition = newPosition;
return true;
}
return false;
}
//************************************************** ***********************
// set Voices Lamp off
//************************************************** ***********************
void set_Voices_Lamp (void)
{
if (voices[0].lampTimeOn == 1){
disp.fillRect(133, 3, 7, 4, ST7735_BLACK);
disp.drawRect(133, 3, 7, 4, ST7735_RED); // Lamp1 off
voices[0].lampTimeOn--;
}
else if (voices[0].lampTimeOn > 1){
voices[0].lampTimeOn--;
}
if (voices[1].lampTimeOn == 1){
disp.fillRect(133+10, 3, 7, 4, ST7735_BLACK);
disp.drawRect(133+10, 3, 7, 4, ST7735_RED); // Lamp2 off
voices[1].lampTimeOn--;
}
else if (voices[1].lampTimeOn > 1){
voices[1].lampTimeOn--;
}
if (voices[2].lampTimeOn == 1){
disp.fillRect(133+20, 3, 7, 4, ST7735_BLACK);
disp.drawRect(133+20, 3, 7, 4, ST7735_RED); // Lamp3 off
voices[2].lampTimeOn--;
}
else if (voices[2].lampTimeOn > 1){
voices[2].lampTimeOn--;
}
if (voices[3].lampTimeOn == 1){
disp.fillRect(133, 11, 7, 4, ST7735_BLACK);
disp.drawRect(133, 11, 7, 4, ST7735_RED); // Lamp4 off
voices[3].lampTimeOn--;
}
else if (voices[3].lampTimeOn > 1){
voices[3].lampTimeOn--;
}
if (voices[4].lampTimeOn == 1){
disp.fillRect(133+10, 11, 7, 4, ST7735_BLACK);
disp.drawRect(133+10, 11, 7, 4, ST7735_RED); // Lamp5 off
voices[4].lampTimeOn--;
}
else if (voices[4].lampTimeOn > 1){
voices[4].lampTimeOn--;
}
if (voices[5].lampTimeOn == 1){
disp.fillRect(133+20, 11, 7, 4, ST7735_BLACK);
disp.drawRect(133+20, 11, 7, 4, ST7735_RED); // Lamp6 off
voices[5].lampTimeOn--;
}
else if (voices[5].lampTimeOn > 1){
voices[5].lampTimeOn--;
}
}
//************************************************** ***********************
// get Voice number
//************************************************** ***********************
int getVoiceNo(int note)
{
voiceToReturn = -1; //Initialise
earliestTime = millis(); //Initialise to now
if (note == -1)
{
//NoteOn() - Get the oldest free voice (recent voices may be still on release stage)
for (int i = 0; i < NO_OF_VOICES; i++)
{
if (voices[i].voiceOn == false)
{
if (voices[i].timeOn < earliestTime)
{
earliestTime = voices[i].timeOn;
voiceToReturn = i;
}
}
}
if (voiceToReturn == -1)
{
//No free voices, need to steal oldest sounding voice
earliestTime = millis(); //Reinitialise
for (int i = 0; i < NO_OF_VOICES; i++)
{
if (voices[i].timeOn < earliestTime)
{
earliestTime = voices[i].timeOn;
voiceToReturn = i;
}
}
}
return voiceToReturn + 1;
}
else
{
//NoteOff() - Get voice number from note
for (int i = 0; i < NO_OF_VOICES; i++)
{
if (voices[i].note == note && voices[i].voiceOn)
{
return i + 1;
}
}
}
//Shouldn't get here, return voice 1
return 1;
}
//************************************************** ***********************
// set Voice on
//************************************************** ***********************
void set_Voice_on(uint8_t note)
{
float freq = 440.0 * powf(2.0, (float)(note - 69) * 0.08333333);
switch(getVoiceNo(-1))
{
case 1:
waveform1.frequency(freq * BendFactor);
waveform1.phase(0);
envelope1_0.noteOn();
envelope1_1.noteOn();
voices[0].note = note;
voices[0].timeOn = millis();
voices[0].voiceOn = true;
disp.fillRect(133, 3, 7, 4, ST7735_RED); // Lamp1 on
break;
case 2:
waveform2.frequency(freq * BendFactor);
waveform2.phase(0);
envelope2_0.noteOn();
envelope2_1.noteOn();
voices[1].note = note;
voices[1].timeOn = millis();
voices[1].voiceOn = true;
disp.fillRect(133+10, 3, 7, 4, ST7735_RED); // Lamp2 on
break;
case 3:
waveform3.frequency(freq * BendFactor);
waveform3.phase(0);
envelope3_0.noteOn();
envelope3_1.noteOn();
voices[2].note = note;
voices[2].timeOn = millis();
voices[2].voiceOn = true;
disp.fillRect(133+20, 3, 7, 4, ST7735_RED); // Lamp3 on
break;
case 4:
waveform4.frequency(freq * BendFactor);
waveform4.phase(0);
envelope4_0.noteOn();
envelope4_1.noteOn();
voices[3].note = note;
voices[3].timeOn = millis();
voices[3].voiceOn = true;
disp.fillRect(133, 11, 7, 4, ST7735_RED); // Lamp4 on
break;
case 5:
waveform5.frequency(freq * BendFactor);
waveform5.phase(0);
envelope5_0.noteOn();
envelope5_1.noteOn();
voices[4].note = note;
voices[4].timeOn = millis();
voices[4].voiceOn = true;
disp.fillRect(133+10, 11, 7, 4, ST7735_RED); // Lamp5 on
break;
case 6:
waveform6.frequency(freq * BendFactor);
waveform6.phase(0);
envelope6_0.noteOn();
envelope6_1.noteOn();
voices[5].note = note;
voices[5].timeOn = millis();
voices[5].voiceOn = true;
disp.fillRect(133+20, 11, 7, 4, ST7735_RED); // Lamp6 on
break;
}
}
//************************************************** ***********************
// set Voices off
//************************************************** ***********************
void set_Voice_off(uint8_t note)
{
switch (getVoiceNo(note))
{
case 1:
envelope1_0.noteOff(); // AMP
envelope1_1.noteOff(); // Filter
voices[0].voiceOn = false;
voices[0].lampTimeOn = 64;
break;
case 2:
envelope2_0.noteOff(); // AMP
envelope2_1.noteOff(); // Filter
voices[1].voiceOn = false;
voices[1].lampTimeOn = 64;;
break;
case 3:
envelope3_0.noteOff(); // AMP
envelope3_1.noteOff(); // Filter
voices[2].voiceOn = false;
voices[2].lampTimeOn = 64;
break;
case 4:
envelope4_0.noteOff(); // AMP
envelope4_1.noteOff(); // Filter
voices[3].voiceOn = false;
voices[3].lampTimeOn = 64;
break;
case 5:
envelope5_0.noteOff(); // AMP
envelope5_1.noteOff(); // Filter
voices[4].voiceOn = false;
voices[4].lampTimeOn = 64;
break;
case 6:
envelope6_0.noteOff(); // AMP
envelope6_1.noteOff(); // Filter
voices[5].voiceOn = false;
voices[5].lampTimeOn = 64;
break;
}
}
//************************************************** ***********************
// set AllNotesOff
//************************************************** ***********************
void set_AllNotesOff(void)
{
voices[0].voiceOn = false;
voices[1].voiceOn = false;
voices[2].voiceOn = false;
voices[3].voiceOn = false;
voices[4].voiceOn = false;
voices[5].voiceOn = false;
envelope1_0.noteOff(); // AMP
envelope1_1.noteOff(); // Filter
envelope2_0.noteOff(); // AMP
envelope2_1.noteOff(); // Filter
envelope3_0.noteOff(); // AMP
envelope3_1.noteOff(); // Filter
envelope5_0.noteOff(); // AMP
envelope5_1.noteOff(); // Filter
envelope6_0.noteOff(); // AMP
envelope6_1.noteOff(); // Filter
}
//************************************************** ***********************
// Midi handel (every 1ms)
//************************************************** ***********************
void midi_handel (void)
{
if (MIDI.read()) { // look for a message
switch (MIDI.getType()) { // get message type
// note on ---------------------------------------------------
case midi::NoteOn:
note = MIDI.getData1();
velocity = MIDI.getData2();
set_Voice_on(note);
break;
// note off --------------------------------------------------
case midi::NoteOff:
note = MIDI.getData1();
velocity = MIDI.getData2();
set_Voice_off(note);
break;
// Contrl: PitchBend -----------------------------------------
case midi::PitchBend:
pitch_bnd = (MIDI.getData2() << 7) + MIDI.getData1();
pitch_bnd = (pitch_bnd - 8192);
bendf = pitch_bnd;
bendf = bendf / 8192;
bendf = bendf * 2;
bendf = bendf / 12;
BendFactor = pow(2, bendf);
waveform1.frequency(freq * BendFactor);
break;
default:
break;
}
}
}
//-------------------------------------------------------------------------
// set Osc values
//-------------------------------------------------------------------------
void set_OSC_values(void)
{
uint8_t pot_temp = 0;
if (pot_1_change == true){
pot_temp = (pot_1 / 18);
waveform1.begin(pot_temp);
waveform2.begin(pot_temp);
waveform3.begin(pot_temp);
waveform4.begin(pot_temp);
waveform5.begin(pot_temp);
waveform6.begin(pot_temp);
disp.setCursor(5,40);
disp.fillRect(5,39,23,8,ST7735_BLACK);
disp.setTextColor(ST7735_WHITE);
disp.print(Waveform_text[pot_temp]);
Osc_waveform = pot_1;
}
if (pot_2_change == true){
}
if (pot_3_change == true){
}
if (pot_4_change == true){
}
}
//************************************************** ***********************
// print pot_value
//************************************************** ***********************
void print_potValue (int pot_temp, uint8_t x, uint8_t y)
{
// sustain only in %
if (x == 84) {
disp.fillRect(x, y, 30, 8, ST7735_BLACK);
disp.setTextColor(ST7735_GRAY);
uint8_t value = ((float)0.79 * pot_temp);
if (value < 10){
disp.setCursor(x + 9, y);
disp.print(value);
disp.print("%");
}
else if (value < 100){
disp.setCursor(x + 6, y);
disp.print(value);
disp.print("%");
}
else if (value >= 100){
disp.setCursor(x + 2, y);
disp.print(value);
disp.print("%");
}
}
// attack, decay and release
else
{
disp.fillRect(x, y, 30, 8, ST7735_BLACK);
disp.setTextColor(ST7735_GRAY);
int value = pot_temp;
if (value < 10) {
disp.setCursor(x + 6, y);
disp.print(value);
disp.print("ms");
}
else if (value < 100) {
disp.setCursor(x + 4,y);
disp.print(value);
disp.print("ms");
}
else if (value < 1000) {
disp.setCursor(x, y);
disp.print(value);
disp.print("ms");
}
else if (value < 10000) {
float val_sec = (float)value / 1000;
disp.drawFloat(val_sec, 1, x, y);
disp.setCursor(x + 24, y);
disp.print("s");
}
else if (value >= 10000) {
uint8_t val_sec = value / 1000;
disp.setCursor(x + 6, y);
disp.print(val_sec);
disp.print("s");
}
}
}
//************************************************** ***********************
// set AMP envelope(1)
///************************************************** **********************
void set_AMP_envelope(void)
{
float pot_temp = 0;
// Delay
/*
envelope1_0.delay(0);
envelope2_0.delay(0);
envelope3_0.delay(0);
envelope4_0.delay(0);
envelope5_0.delay(0);
envelope6_0.delay(0);
*/
// Attack
if (pot_1_change == true){
pot_temp = (Pot_PowerTab[pot_1]);
envelope1_0.attack(pot_temp);
envelope2_0.attack(pot_temp);
envelope3_0.attack(pot_temp);
envelope4_0.attack(pot_temp);
envelope5_0.attack(pot_temp);
envelope6_0.attack(pot_temp);
Amp_env_att = pot_1;
print_potValue(pot_temp,4,120);
}
// Hold
/*
envelope1_0.hold(0);
envelope2_0.hold(0);
envelope3_0.hold(0);
envelope4_0.hold(0);
envelope5_0.hold(0);
envelope6_0.hold(0);
*/
// Decay
if (pot_2_change == true){
pot_temp = (Pot_PowerTab[pot_2]);
envelope1_0.decay(pot_temp);
envelope2_0.decay(pot_temp);
envelope3_0.decay(pot_temp);
envelope4_0.decay(pot_temp);
envelope5_0.decay(pot_temp);
envelope6_0.decay(pot_temp);
Amp_env_dcy = pot_2;
print_potValue(pot_temp, 4+40, 120);
}
// Sustain
if (pot_3_change == true){
if (pot_3 <= 2)
{
pot_3 = 0;
}
pot_temp = (0.008 * pot_3);
envelope1_0.sustain(pot_temp);
envelope2_0.sustain(pot_temp);
envelope3_0.sustain(pot_temp);
envelope4_0.sustain(pot_temp);
envelope5_0.sustain(pot_temp);
envelope6_0.sustain(pot_temp);
Amp_env_sus = pot_3;
print_potValue(pot_3, 4+40+40, 120);
}
// Release
if (pot_4_change == true){
pot_temp = (Pot_PowerTab[pot_4]);
envelope1_0.release(pot_temp);
envelope2_0.release(pot_temp);
envelope3_0.release(pot_temp);
envelope4_0.release(pot_temp);
envelope5_0.release(pot_temp);
envelope6_0.release(pot_temp);
Amp_env_rel = pot_4;
print_potValue(pot_temp, 4+40+40+40, 120);
}
}
//-------------------------------------------------------------------------
// set Filter envelope(2)
//-------------------------------------------------------------------------
void set_Filter_envelope(void)
{
float pot_temp = 0;
// Delay
/*
envelope1_1.delay(0);
envelope2_1.delay(0);
envelope3_1.delay(0);
envelope4_1.delay(0);
envelope5_1.delay(0);
envelope6_1.delay(0);
*/
// Attack
if (pot_1_change == true){
pot_temp = (Pot_PowerTab[pot_1]);
envelope1_1.attack(pot_temp);
envelope2_1.attack(pot_temp);
envelope3_1.attack(pot_temp);
envelope4_1.attack(pot_temp);
envelope5_1.attack(pot_temp);
envelope6_1.attack(pot_temp);
Filter_env_att = pot_1;
print_potValue(pot_temp,4,120);
}
// Hold
/*
envelope1_1.hold(0);
envelope2_1.hold(0);
envelope3_1.hold(0);
envelope4_1.hold(0);
envelope5_1.hold(0);
envelope6_1.hold(0);
*/
// Decay
if (pot_2_change == true){
pot_temp = (Pot_PowerTab[pot_2]);
envelope1_1.decay(pot_temp);
envelope2_1.decay(pot_temp);
envelope3_1.decay(pot_temp);
envelope4_1.decay(pot_temp);
envelope5_1.decay(pot_temp);
envelope6_1.decay(pot_temp);
Filter_env_dcy = pot_2;
print_potValue(pot_temp, 4+40, 120);
}
// Sustain
if (pot_3_change == true){
if (pot_3 <= 2)
{
pot_3 = 0;
}
pot_temp = (0.008 * pot_3);
envelope1_1.sustain(pot_temp);
envelope2_1.sustain(pot_temp);
envelope3_1.sustain(pot_temp);
envelope4_1.sustain(pot_temp);
envelope5_1.sustain(pot_temp);
envelope6_1.sustain(pot_temp);
Filter_env_sus = pot_3;
print_potValue(pot_3, 4+40+40, 120);
}
// Release
if (pot_4_change == true){
pot_temp = (Pot_PowerTab[pot_4]);
envelope1_1.release(pot_temp);
envelope2_1.release(pot_temp);
envelope3_1.release(pot_temp);
envelope4_1.release(pot_temp);
envelope5_1.release(pot_temp);
envelope6_1.release(pot_temp);
Filter_env_rel = pot_4;
print_potValue(pot_temp, 4+40+40+40, 120);
}
}
//************************************************** ***********************
// set Filter envelope(2)
//************************************************** ***********************
void set_Filter_values(void)
{
float pot_temp = 0;
int pot_value = 0;
// set frequency
if (pot_1_change == true){
for (uint8_t i = 0; i < 16; i++){
analog1.update();
pot_value = pot_value + ((analog1.getValue()) >> 2);
}
pot_value = pot_value / 16;
pot_temp = (FilterFrequency[pot_value]);
filter1.frequency(pot_temp);
filter2.frequency(pot_temp);
filter3.frequency(pot_temp);
filter4.frequency(pot_temp);
filter5.frequency(pot_temp);
filter6.frequency(pot_temp);
Filter_cut = pot_1;
disp.fillRect(4, 120, 30, 8, ST7735_BLACK);
disp.setTextColor(ST7735_GRAY);
int value = pot_temp;
if (value < 100){
disp.setCursor(8, 120);
disp.print(value);
disp.print("Hz");
}
else if (value < 1000){
disp.setCursor(4, 120);
disp.print(value);
disp.print("Hz");
}
else if (value < 10000){
value = value / 1000;
disp.setCursor(6, 120);
disp.print(value);
disp.print("KHz");
}
else if (value < 100000){
value = value / 1000;
disp.setCursor(4, 120);
disp.print(value);
disp.print("KHz");
}
}
// set resonance
if (pot_2_change == true){
pot_temp = (0.039 * pot_2);
filter1.resonance(pot_temp);
filter2.resonance(pot_temp);
filter3.resonance(pot_temp);
filter4.resonance(pot_temp);
filter5.resonance(pot_temp);
filter6.resonance(pot_temp);
Filter_res = pot_2;
disp.fillRect(44, 120, 30, 8, ST7735_BLACK);
disp.setTextColor(ST7735_GRAY);
uint8_t value = ((float)0.79 * pot_2);
if (value < 10){
disp.setCursor(44 + 9, 120);
disp.print(value);
disp.print("%");
}
else if (value < 100){
disp.setCursor(44 + 6, 120);
disp.print(value);
disp.print("%");
}
else if (value >= 100){
disp.setCursor(44 + 2, 120);
disp.print(value);
disp.print("%");
}
}
// set KeyTracking
if (pot_3_change == true){
pot_value = 0;
for (uint8_t i = 0; i < 16; i++){
analog3.update();
pot_value = pot_value + ((analog3.getValue()) >> 2);
}
pot_value = pot_value / 16;
/*
pot_temp = (0.055 * pot_3);
filter1.octaveControl(pot_temp);
filter2.octaveControl(pot_temp);
filter3.octaveControl(pot_temp);
filter4.octaveControl(pot_temp);
filter5.octaveControl(pot_temp);
filter6.octaveControl(pot_temp);
*/
Filter_key = pot_3;
disp.fillRect(84, 120, 30, 8, ST7735_BLACK);
disp.setTextColor(ST7735_GRAY);
int value = (pot_value * 0.785) - 100;
if (value == 0){
disp.setCursor(84 + 12, 120);
disp.print(value);
}
else if (value > -10 && value < 0){
disp.setCursor(84 + 8, 120);
disp.print(value);
}
else if (value > -100 && value < 0){
disp.setCursor(84 + 6, 120);
disp.print(value);
}
else if (value > 0 && value < 10){
disp.setCursor(84 + 8, 120);
disp.print("+");
disp.print(value);
}
else if (value >= 10 && value < 100){
disp.setCursor(84 + 6, 120);
disp.print("+");
disp.print(value);
}
//disp.print("+");
}
// set Filter Typ
if (pot_4_change == true){
set_Filter_typ();
}
}
//************************************************** ***********************
// init System
//************************************************** ***********************
void setup() {
// init 1.8" TFT ------------------------------------
disp.initR(INITR_BLACKTAB);
disp.fillScreen(ST7735_BLACK);
disp.setTextColor(ST7735_YELLOW, ST7735_BLACK);
disp.setRotation(3);
disp.setTextWrap(false);
disp.setTextSize(2);
disp.setCursor(20, 40);
disp.print("SHRUTHI II");
disp.setTextSize(0);
disp.setCursor(60, 70);
disp.print("V 1.02");
// init Audio and Waveform -------------------------------------------
AudioMemory(48);
sgtl5000_1.enable();
sgtl5000_1.volume(0.9);
sgtl5000_1.audioPostProcessorEnable();
sgtl5000_1.enhanceBassEnable();
sgtl5000_1.enhanceBass(0.85, 0.85, 0, 2); // high Bass + HP-Filter
waveform1.begin(0); // SINE
waveform2.begin(0); // SINE
waveform3.begin(0); // SINE
waveform4.begin(0); // SINE
waveform5.begin(0); // SINE
waveform6.begin(0); // SINE
waveform1.frequency(440);
waveform2.frequency(440);
waveform3.frequency(440);
waveform4.frequency(440);
waveform5.frequency(440);
waveform6.frequency(440);
waveform1.amplitude(0.5);
waveform2.amplitude(0.5);
waveform3.amplitude(0.5);
waveform4.amplitude(0.5);
waveform5.amplitude(0.5);
waveform6.amplitude(0.5);
// init Envelopes ---------------------------------------------------
envelope1_0.delay(0);
envelope2_0.delay(0);
envelope3_0.delay(0);
envelope4_0.delay(0);
envelope5_0.delay(0);
envelope6_0.delay(0);
envelope1_0.attack(0);
envelope2_0.attack(0);
envelope3_0.attack(0);
envelope4_0.attack(0);
envelope5_0.attack(0);
envelope6_0.attack(0);
envelope1_0.hold(0);
envelope2_0.hold(0);
envelope3_0.hold(0);
envelope4_0.hold(0);
envelope5_0.hold(0);
envelope6_0.hold(0);
envelope1_0.decay(5);
envelope2_0.decay(5);
envelope3_0.decay(5);
envelope4_0.decay(5);
envelope5_0.decay(5);
envelope6_0.decay(5);
envelope1_0.sustain(0.7);
envelope2_0.sustain(0.7);
envelope3_0.sustain(0.7);
envelope4_0.sustain(0.7);
envelope5_0.sustain(0.7);
envelope6_0.sustain(0.7);
envelope1_0.release(50);
envelope2_0.release(50);
envelope3_0.release(50);
envelope4_0.release(50);
envelope5_0.release(50);
envelope6_0.release(50);
envelope1_1.delay(0);
envelope2_1.delay(0);
envelope3_1.delay(0);
envelope4_1.delay(0);
envelope5_1.delay(0);
envelope6_1.delay(0);
envelope1_1.attack(0);
envelope2_1.attack(0);
envelope3_1.attack(0);
envelope4_1.attack(0);
envelope5_1.attack(0);
envelope6_1.attack(0);
envelope1_1.hold(0);
envelope2_1.hold(0);
envelope3_1.hold(0);
envelope4_1.hold(0);
envelope5_1.hold(0);
envelope6_1.hold(0);
envelope1_1.decay(5);
envelope2_1.decay(5);
envelope3_1.decay(5);
envelope4_1.decay(5);
envelope5_1.decay(5);
envelope6_1.decay(5);
envelope1_1.sustain(0.7);
envelope2_1.sustain(0.7);
envelope3_1.sustain(0.7);
envelope4_1.sustain(0.7);
envelope5_1.sustain(0.7);
envelope6_1.sustain(0.7);
envelope1_1.release(50);
envelope2_1.release(50);
envelope3_1.release(50);
envelope4_1.release(50);
envelope5_1.release(50);
envelope6_1.release(50);
Amp_env_att = 0;
Amp_env_dcy = 30;
Amp_env_sus = 95;
Amp_env_rel = 30;
Filter_env_att = 0;
Filter_env_dcy = 30;
Filter_env_sus = 95;
Filter_env_rel = 30;
Filter_cut = 80;
Filter_res = 30;
Filter_key = 50;
Filter_typ = 0;
dc1.amplitude(1.0);
dc2.amplitude(1.0);
dc3.amplitude(1.0);
dc4.amplitude(1.0);
dc5.amplitude(1.0);
dc6.amplitude(1.0);
// Mixer 1-6 (Filter) ------------------------------------------------
mixer1.gain(0, 1.0); // LP
mixer1.gain(1, 0); // BP
mixer1.gain(2, 0); // HP
mixer1.gain(3, 0); // --
mixer2.gain(0, 1.0); // LP
mixer2.gain(1, 0); // BP
mixer2.gain(2, 0); // HP
mixer2.gain(3, 0); // --
mixer3.gain(0, 1.0); // LP
mixer3.gain(1, 0); // BP
mixer3.gain(2, 0); // HP
mixer3.gain(3, 0); // --
mixer4.gain(0, 1.0); // LP
mixer4.gain(1, 0); // BP
mixer4.gain(2, 0); // HP
mixer4.gain(3, 0); // --
mixer5.gain(0, 1.0); // LP
mixer5.gain(1, 0); // BP
mixer5.gain(2, 0); // HP
mixer5.gain(3, 0); // --
mixer6.gain(0, 1.0); // LP
mixer6.gain(1, 0); // BP
mixer6.gain(2, 0); // HP
mixer6.gain(3, 0); // --
// Mixer AMP ---------------------------------------------------------
mixer20.gain(0, 0.85); // Osc1
mixer20.gain(1, 0.85); // Osc2
mixer20.gain(2, 0.85); // Osc3
mixer20.gain(3, 0.85); // Osc4
mixer21.gain(0, 0.85); // Osc5
mixer21.gain(1, 0.85); // Osc6
mixer21.gain(2, 0); // --
mixer21.gain(3, 0); // --
mixer22.gain(0, 0.85); // Sum1
mixer22.gain(1, 0.85); // Sum2
mixer22.gain(2, 0); // --
mixer22.gain(3, 0); // --
// Filter ------------------------------------------------------------
filter1.frequency(2000);
filter2.frequency(2000);
filter3.frequency(2000);
filter4.frequency(2000);
filter5.frequency(2000);
filter6.frequency(2000);
filter1.resonance(2.5);
filter2.resonance(2.5);
filter3.resonance(2.5);
filter4.resonance(2.5);
filter5.resonance(2.5);
filter6.resonance(2.5);
filter1.octaveControl(7.0);
filter2.octaveControl(7.0);
filter3.octaveControl(7.0);
filter4.octaveControl(7.0);
filter5.octaveControl(7.0);
filter6.octaveControl(7.0);
//--------------------------------------------------
//init analog Inputs
pinMode(14, INPUT_DISABLE);
pinMode(16, INPUT_DISABLE);
pinMode(17, INPUT_DISABLE);
pinMode(22, INPUT_DISABLE);
//analogReadResolution(12);
//analogReadAveraging(16);
//---------------------------------------------------
// init Encoder
//myEnc.begin(0, 0, 9); // will start at 20 and go from 0 to 40
// --------------------------------------------------
// init Midi and clear Note_buffers
MIDI.begin(channel);
set_AllNotesOff();
//---------------------------------------------------
// draw first menu site
for (uint8_t i = 0; i <= 5; i++)
{
read_pots();
}
pot_1_change = false;
pot_2_change = false;
pot_3_change = false;
pot_4_change = false;
Osc_menu();
}
//************************************************** ***********************
// Main loop
//************************************************** ***********************
void loop() {
unsigned long currentMillis = millis();
// read Midi datas (every 1ms) --------------------------------------
if (currentMillis - previousTime_midi >= interval_midi){
midi_handel();
set_Voices_Lamp();
previousTime_midi = currentMillis;
}
// read ADC (every 15ms) --------------------------------------------
if (currentMillis - previousTime_ADC >= interval_ADC){
analog1.update();
analog2.update();
analog3.update();
analog4.update();
previousTime_ADC = currentMillis;
}
// read Encoder and Potentiometers (every 25ms) --------------------
if (currentMillis - previousTime_pot >= interval_pot){
if(read_Encoder() == true){ // Encoder menu site
Menu_page = oldPosition;
if(Menu_page == Menu_Osc){
Osc_menu();
}
else if(Menu_page == Menu_AmpEnv){
AMP_envelope_menu();
}
else if(Menu_page == Menu_FilterEnv){
Filter_envelope_menu();
}
else if(Menu_page == Menu_Filter){
Filter_menu();
}
}
// read Potentiometers
if (read_pots() == true){
if (Menu_page == Menu_Osc){
set_OSC_values();
}
else if (Menu_page == Menu_AmpEnv){
set_AMP_envelope();
draw_AMP_envLine();
refresh_pot_values();
}
else if (Menu_page == Menu_FilterEnv){
set_Filter_envelope();
draw_Filter_envLine();
refresh_pot_values();
}
else if (Menu_page == Menu_Filter){
set_Filter_values();
draw_filter_curves(Filter_typ);
refresh_pot_values();
}
}
}
// Measurement CPU usage (every 200ms) ------------------------------
if (currentMillis - previousTime_cpu >= interval_cpu) {
print_CPU_usage();
previousTime_cpu = currentMillis;
}
}
/*
// seriell print ----------------------------------------------------------
Serial.println();
*/