CVtoOSC Converter for Nucleo F303K8

Dependencies:   DebouncedInterrupt MIDI mbed osc-cnmat BufferedSerial

OSC to CV Converter

http://gtbts.tumblr.com/post/142840140501/cvtoosc-converter-for-modular-synthesizer

Revision:
0:577ad245b1f5
Child:
1:0a963a78f2bd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Feb 14 03:32:40 2016 +0000
@@ -0,0 +1,681 @@
+/*
+    CVtoOSC&MIDI Converter for Nucleo F303K8
+    https://developer.mbed.org/platforms/ST-Nucleo-F303K8/
+*/
+
+#pragma O3
+#pragma Otime
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+#include <string>
+
+#include "mbed.h"
+#include "DebouncedInterrupt.h"
+#include "MIDI.h"
+#include "OSCBundle.h"
+
+//-------------------------------------------------------------
+// Macros
+
+#define MIDI_OFFSET          4
+#define MAP_OFFSET           0
+#define CALIB_OFFSET        37
+
+#define QUAN_RES1          116      // Quantize voltage Steps
+#define QUAN_RES2           68
+#define QUAN_RES3           46
+#define QUAN_RES4           40
+#define QUAN_RES5           68
+#define QUAN_RES6           68  
+#define QUAN_RES7           16
+#define QUAN_RES8           58
+
+#define Lin                 0        // Linear LinearCV
+#define Chr                 1        // Chromatic
+#define Maj                 2        // Major
+#define M7                  3        // Major7
+#define Min7                4        // Minor7
+#define Dor                 5        // Dorian
+#define Min                 6        // Minor
+#define S5th                7        // 5th
+#define Wht                 8        // Wholetone
+
+#define SCALE_TOTAL         9
+
+#define SEND_BUFF_SIZE    384        // OSC send buffer size
+#define WAIT_SEND          20        // wait time(ms) for esp8266 transmission complete
+
+#define MIDI_CHANNEL        1        // MIDI channel
+
+//-------------------------------------------------------------
+// Global Variables
+
+// Silentway Calibration Data Mapping
+// http://www.expert-sleepers.co.uk/silentway.html
+
+//  Chromatic Scale
+const float calibMap1[QUAN_RES1] = {
+0.00076928,   0.00900736,   0.01724544,   0.02548352,   0.03372160,
+0.04195968,   0.05019776,   0.05843584,   0.06667392,   0.07491200,
+0.08315008,   0.09138816,   0.09962624,   0.10786432,   0.11610240,
+0.12434047,   0.13258974,   0.14083999,   0.14909023,   0.15734047,
+0.16559070,   0.17384095,   0.18209119,   0.19034143,   0.19859168,
+0.20684192,   0.21509215,   0.22334240,   0.23159264,   0.23984288,
+0.24809311,   0.25634655,   0.26460093,   0.27285531,   0.28110969,
+0.28936407,   0.29761845,   0.30587283,   0.31412721,   0.32238159,
+0.33063596,   0.33889034,   0.34714472,   0.35539910,   0.36365348,
+0.37190786,   0.38017464,   0.38844886,   0.39672306,   0.40499726,
+0.41327149,   0.42154568,   0.42981988,   0.43809411,   0.44636831,
+0.45464250,   0.46291673,   0.47119093,   0.47946513,   0.48773935,
+0.49601355,   0.50430328,   0.51260746,   0.52091163,   0.52921581,
+0.53751999,   0.54582411,   0.55412829,   0.56243247,   0.57073665,
+0.57904083,   0.58734500,   0.59564912,   0.60395330,   0.61225748,
+0.62056166,   0.62890279,   0.63728637,   0.64566994,   0.65405351,
+0.66243708,   0.67082065,   0.67920423,   0.68758780,   0.69597137,
+0.70435494,   0.71273851,   0.72112209,   0.72950566,   0.73788923,
+0.74627280,   0.75476575,   0.76334614,   0.77192658,   0.78050703,
+0.78908741,   0.79766786,   0.80624831,   0.81482869,   0.82340914,
+0.83198959,   0.84056997,   0.84915042,   0.85773087,   0.86631125,
+0.87489170,   0.88425636,   0.89363104,   0.90300572,   0.91238040,
+0.92175508,   0.93112975,   0.94050443,   0.94987911,   0.95925385,
+0.96862853
+};
+
+//  Major Scale
+const float calibMap2[QUAN_RES2] = {
+calibMap1[0], calibMap1[2], calibMap1[4], calibMap1[5], calibMap1[7],
+calibMap1[9], calibMap1[11], calibMap1[12], calibMap1[14], calibMap1[16],
+calibMap1[17], calibMap1[19], calibMap1[21], calibMap1[23], calibMap1[24],
+calibMap1[26], calibMap1[28], calibMap1[29], calibMap1[31], calibMap1[33],
+calibMap1[35], calibMap1[36], calibMap1[38], calibMap1[40], calibMap1[41],
+calibMap1[43], calibMap1[45], calibMap1[47], calibMap1[48], calibMap1[50],
+calibMap1[52], calibMap1[53], calibMap1[55], calibMap1[57], calibMap1[59],
+calibMap1[60], calibMap1[62], calibMap1[64], calibMap1[65], calibMap1[67],
+calibMap1[69], calibMap1[71], calibMap1[72], calibMap1[74], calibMap1[76],
+calibMap1[77], calibMap1[79], calibMap1[81], calibMap1[83], calibMap1[84],
+calibMap1[86], calibMap1[88], calibMap1[89], calibMap1[91], calibMap1[93],
+calibMap1[95], calibMap1[96], calibMap1[98], calibMap1[100], calibMap1[101],
+calibMap1[103], calibMap1[105], calibMap1[107], calibMap1[108], calibMap1[110],
+calibMap1[112], calibMap1[113], calibMap1[115]
+};
+
+//  M7(9)
+const float calibMap3[QUAN_RES3] = {
+calibMap1[0],  calibMap1[4], calibMap1[7], calibMap1[11], calibMap1[12], 
+calibMap1[14], calibMap1[16], calibMap1[19], calibMap1[23], calibMap1[24],
+calibMap1[26], calibMap1[28], calibMap1[31], calibMap1[35], calibMap1[36], 
+calibMap1[38], calibMap1[40], calibMap1[43], calibMap1[47], calibMap1[48], 
+calibMap1[50], calibMap1[52], calibMap1[55], calibMap1[59], calibMap1[60], 
+calibMap1[62], calibMap1[64], calibMap1[67], calibMap1[71], calibMap1[72], 
+calibMap1[76], calibMap1[79], calibMap1[83], calibMap1[84], calibMap1[86], 
+calibMap1[88], calibMap1[91], calibMap1[95], calibMap1[96], calibMap1[100],
+calibMap1[103], calibMap1[107], calibMap1[108], calibMap1[110], calibMap1[112], 
+calibMap1[115]
+};
+
+//  m7(9)
+const float calibMap4[QUAN_RES4] = {
+calibMap1[0], calibMap1[3], calibMap1[7], calibMap1[10], calibMap1[12], 
+calibMap1[15], calibMap1[19], calibMap1[22], calibMap1[26], calibMap1[27], 
+calibMap1[31], calibMap1[34], calibMap1[36], calibMap1[38], calibMap1[39], 
+calibMap1[43], calibMap1[46], calibMap1[50], calibMap1[53], calibMap1[55], 
+calibMap1[58], calibMap1[60], calibMap1[63], calibMap1[67], calibMap1[70], 
+calibMap1[72], calibMap1[74], calibMap1[75], calibMap1[79], calibMap1[82], 
+calibMap1[86], calibMap1[89], calibMap1[91], calibMap1[94], calibMap1[96], 
+calibMap1[99],  calibMap1[103], calibMap1[106], calibMap1[110], calibMap1[113]
+};
+
+//  Dorian Scale
+const float calibMap5[QUAN_RES5] = {
+calibMap1[0], calibMap1[2], calibMap1[3], calibMap1[5], calibMap1[7],
+calibMap1[9], calibMap1[10], calibMap1[12], calibMap1[14], calibMap1[15],
+calibMap1[17], calibMap1[19], calibMap1[20], calibMap1[21], calibMap1[24],
+calibMap1[26], calibMap1[27], calibMap1[29], calibMap1[31], calibMap1[33],
+calibMap1[34], calibMap1[36], calibMap1[38], calibMap1[39], calibMap1[41],
+calibMap1[43], calibMap1[45], calibMap1[46], calibMap1[48], calibMap1[50],
+calibMap1[51], calibMap1[53], calibMap1[55], calibMap1[57], calibMap1[58],
+calibMap1[60], calibMap1[62], calibMap1[63], calibMap1[65], calibMap1[67],
+calibMap1[69], calibMap1[70], calibMap1[72], calibMap1[74], calibMap1[75],
+calibMap1[77], calibMap1[79], calibMap1[81], calibMap1[82], calibMap1[84],
+calibMap1[86], calibMap1[87], calibMap1[89], calibMap1[91], calibMap1[93],
+calibMap1[94], calibMap1[96], calibMap1[98], calibMap1[99], calibMap1[101],
+calibMap1[103], calibMap1[105], calibMap1[106], calibMap1[108], calibMap1[110],
+calibMap1[111], calibMap1[113], calibMap1[115]
+};
+
+//  Minor Scale
+const float calibMap6[QUAN_RES6] = {
+calibMap1[0], calibMap1[2], calibMap1[3], calibMap1[5], calibMap1[7],
+calibMap1[8], calibMap1[10], calibMap1[12], calibMap1[14], calibMap1[15],
+calibMap1[17], calibMap1[19], calibMap1[20], calibMap1[22], calibMap1[24],
+calibMap1[26], calibMap1[27], calibMap1[29], calibMap1[31], calibMap1[32],
+calibMap1[34], calibMap1[36], calibMap1[38], calibMap1[39], calibMap1[41],
+calibMap1[43], calibMap1[44], calibMap1[46], calibMap1[48], calibMap1[50],
+calibMap1[51], calibMap1[53], calibMap1[55], calibMap1[56], calibMap1[58],
+calibMap1[60], calibMap1[62], calibMap1[63], calibMap1[65], calibMap1[67],
+calibMap1[68], calibMap1[70], calibMap1[72], calibMap1[74], calibMap1[75],
+calibMap1[77], calibMap1[79], calibMap1[80], calibMap1[82], calibMap1[84],
+calibMap1[86], calibMap1[87], calibMap1[89], calibMap1[91], calibMap1[92],
+calibMap1[94], calibMap1[96], calibMap1[98], calibMap1[99], calibMap1[101],
+calibMap1[103], calibMap1[104], calibMap1[106], calibMap1[108], calibMap1[110],
+calibMap1[111], calibMap1[113], calibMap1[115]
+};
+
+//  5th
+const float calibMap7[QUAN_RES7] = {
+calibMap1[0], calibMap1[7], calibMap1[14], calibMap1[21], calibMap1[28],
+calibMap1[35], calibMap1[42], calibMap1[49], calibMap1[56], calibMap1[63],
+calibMap1[70], calibMap1[77], calibMap1[84], calibMap1[91], calibMap1[98],
+calibMap1[105]
+};
+
+//  Whole tone
+const float calibMap8[QUAN_RES8] = {
+calibMap1[0], calibMap1[1], calibMap1[2], calibMap1[6], calibMap1[8],
+calibMap1[10], calibMap1[12], calibMap1[14], calibMap1[16], calibMap1[18],
+calibMap1[20], calibMap1[22], calibMap1[24], calibMap1[26], calibMap1[28],
+calibMap1[30], calibMap1[32], calibMap1[34], calibMap1[36], calibMap1[38],
+calibMap1[40], calibMap1[42], calibMap1[44], calibMap1[46], calibMap1[48],
+calibMap1[50], calibMap1[52], calibMap1[54], calibMap1[56], calibMap1[58],
+calibMap1[60], calibMap1[62], calibMap1[64], calibMap1[66], calibMap1[68],
+calibMap1[70], calibMap1[72], calibMap1[74], calibMap1[76], calibMap1[78],
+calibMap1[80], calibMap1[82], calibMap1[84], calibMap1[86], calibMap1[88],
+calibMap1[90], calibMap1[92], calibMap1[94], calibMap1[96], calibMap1[98],
+calibMap1[100], calibMap1[102], calibMap1[104], calibMap1[106], calibMap1[108],
+calibMap1[110], calibMap1[112], calibMap1[114]
+};
+
+//  Major Scale
+const uint8_t calibMapMidi2[QUAN_RES2] = {
+0, 2, 4, 5, 7, 9, 11, 
+12, 14, 16, 17, 19, 21, 23, 
+24, 26, 28, 29, 31, 33, 35, 
+36, 38, 40, 41, 43, 45, 47, 
+48, 50, 52, 53, 55, 57, 59,
+60, 62, 64, 65, 67, 69, 71, 
+72, 74, 76, 77, 79, 81, 83, 
+84, 86, 88, 89, 91, 93, 95, 
+96, 98, 100, 101, 103, 105, 107, 
+108, 110, 112, 113, 115
+};
+
+//  M7(9)
+const uint8_t calibMapMidi3[QUAN_RES3] = {
+0,  4, 7, 11, 
+12, 14, 16, 19, 23, 
+24, 26, 28, 31, 35,
+36, 38, 40, 43, 47, 
+48, 50, 52, 55, 59, 
+60, 62, 64, 67, 71, 
+72, 76, 79, 83, 
+84, 86, 88, 91, 95, 
+96, 100, 103, 107, 
+108, 110, 112, 115
+};
+
+//  m7(9)
+const uint8_t calibMapMidi4[QUAN_RES4] = {
+0, 3, 7, 10, 
+12, 15, 19, 22, 
+26, 27, 31, 34, 
+36, 38, 39, 43, 46, 
+50, 53, 55, 58, 
+60, 63, 67, 70, 
+72, 74, 75, 79, 82, 
+86, 89, 91, 94, 
+96, 99, 103, 106, 110, 113
+};
+
+//  Dorian Scale
+const uint8_t calibMapMidi5[QUAN_RES5] = {
+0, 2, 3, 5, 7, 9, 10, 
+12, 14, 15, 17, 19, 20, 21, 
+24, 26, 27, 29, 31, 33, 34, 
+36, 38, 39, 41, 43, 45, 46, 
+48, 50, 51, 53, 55, 57, 58, 
+60, 62, 63, 65, 67, 69, 70, 
+72, 74, 75, 77, 79, 81, 82, 
+84, 86, 87, 89, 91, 93, 94, 
+96, 98, 99, 101, 103, 105, 106, 
+108, 110, 111, 113, 115
+};
+
+//  Minor Scale
+const uint8_t calibMapMidi6[QUAN_RES6] = {
+0, 2, 3, 5, 7, 8, 10, 
+12, 14, 15, 17, 19, 20, 22, 
+24, 26, 27, 29, 31, 32, 34, 
+36, 38, 39, 41, 43, 44, 46, 
+48, 50, 51, 53, 55, 56, 58,
+60, 62, 63, 65, 67, 68, 70, 
+72, 74, 75, 77, 79, 80, 82, 
+84, 86, 87, 89, 91, 92, 94, 
+96, 98, 99, 101, 103, 104, 106, 
+108, 110, 111, 113, 115
+};
+
+//  5th
+const uint8_t calibMapMidi7[QUAN_RES7] = {
+0, 7, 14, 21, 28, 35, 
+42, 49, 56, 63, 70, 77, 
+84, 91, 98, 105
+};
+
+//  Whole tone
+const uint8_t calibMapMidi8[QUAN_RES8] = {
+0, 1, 2, 6, 8, 10, 
+12, 14, 16, 18,20, 22, 
+24, 26, 28, 30, 32, 34,  
+36, 38, 40, 42, 44, 46, 
+48, 50, 52, 54, 56, 58, 
+60, 62, 64, 66, 68, 70, 
+72, 74, 76, 78, 80, 82, 
+84, 86, 88, 90, 92, 94, 
+96, 98, 100, 102, 104, 106, 
+108, 110, 112, 114
+};
+
+volatile bool changeFlag = false;
+
+//-------------------------------------------------------------
+// mbed Functions
+/*
+//Nucleo F303K8  //MCP3204
+CS  : pin 10 --  pin 8 (CS/SHDN)
+MOSI: pin 11 --  pin 9 (D in)
+MISO: pin 12 --  pin 10(D out)
+SCK : pin 13 --  pin 11(CLK)
+*/
+SPI          spi(D11, D12, D13);
+DigitalOut   csPin(D10);
+
+AnalogIn     scalePin(A0); // Scale Pin 
+
+AnalogIn     potPin1(A1);     // Pot1~2
+AnalogIn     potPin2(D6);
+
+DebouncedInterrupt switch1(D8);   // SW1
+DebouncedInterrupt switch2(D9);   // SW2
+
+// esp8266 wi-fi settings
+#define SSID        "SSID"
+#define PASSWORD    "PASSWORD"
+
+#define REMOTE_ADDRESS   "192.168.1.2"
+#define REMOTE_PORT      "8000"
+
+//#define STATIC_IP // if you use DHCP comment out this line 
+
+#define LOCAL_ADDRESS    "192.168.1.8"
+#define LOCAL_PORT       "9000"
+
+// Serial for esp8266 (tx, rx)
+Serial esp8266Serial(D1, D0);
+
+// Serial for debug (tx, rx)
+Serial pc(USBTX, USBRX);
+
+// MIDI (tx, rx)
+MIDI midi(A7, A2);
+
+// declare the OSC bundle
+OSCBundle bndl;
+
+// Timer
+Timer timer;
+
+//-------------------------------------------------------------
+// Functions
+
+int map(int, int, int, int, int);
+uint16_t adcRead(uint8_t);
+void interruptSW1();
+void interruptSW2();
+void getESP8266Response();
+void connectWifi();
+
+
+//-------------------------------------------------------------
+// Remaps value from one range to another range.
+
+inline int map(int x, int in_min, int in_max, int out_min, int out_max)
+{
+  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+//-------------------------------------------------------------
+// Read MCP3208 AD Converter
+
+uint16_t adcRead(uint8_t ch) {
+    uint8_t b1, b2;
+    uint8_t address = 0B01100000 | ((ch & 0B11) << 2);
+    
+    csPin = 0; // CS pin Low
+    
+    spi.write(address);
+    b1 = spi.write(0x00);
+    b2 = spi.write(0x00);
+
+    csPin = 1; // CS pin Hi
+        
+    return (b1 << 4) | (b2 >> 4);
+}
+
+//-------------------------------------------------------------
+// Check SW Status
+
+void interruptSW1() {
+    volatile static uint8_t sw1State;
+        
+    if (!sw1State) {
+                 
+        sw1State = 1;
+            
+    } else {
+        
+        sw1State = 0;
+    }
+    
+    bndl.add("/sw1").add(sw1State);
+    changeFlag = true;
+}
+
+void interruptSW2() {
+    volatile static uint8_t sw2State;
+    
+    if (!sw2State) {
+                 
+        sw2State = 1;
+            
+    } else {
+
+        sw2State = 0;
+    }
+    
+    bndl.add("/sw2").add(sw2State);
+    changeFlag = true;
+}
+
+//-------------------------------------------------------------
+//  get & print esp8266 response
+
+void getESP8266Response(int timeout)
+{
+    char resBuff[256] = {0};
+    
+    timer.start();
+    
+    uint8_t i = 0;
+    
+    while (!(timer.read() > timeout)) {
+        
+        if (esp8266Serial.readable()) {
+            
+            resBuff[i++] = esp8266Serial.getc();
+        }
+    }
+    
+    pc.printf(resBuff);
+    
+    timer.stop();
+    timer.reset();
+}
+
+//-------------------------------------------------------------
+// Setup esp8266 wi-fi module
+
+void connectWifi() {
+    
+    pc.printf("\n---------- Starting ESP8266 Config ----------\r\n");
+    wait(2);
+    
+    // set station mode
+    pc.printf("\n---------- Set Station Mode ----------\r\n");
+    
+    esp8266Serial.printf("AT+CWMODE=1\r\n");
+    
+    getESP8266Response(1);
+    wait(1);
+    
+    // restart
+    pc.printf("\n---------- Reset ESP8266 ----------\r\n");
+    
+    esp8266Serial.printf("AT+RST\r\n");
+    
+    getESP8266Response(2);    
+    wait(1);
+    
+#ifdef STATIC_IP
+    
+    // set static IP
+    pc.printf("\n---------- Setting Static IP ----------\r\n");
+    
+    esp8266Serial.printf("AT+CIPSTA=\"");
+    esp8266Serial.printf(LOCAL_ADDRESS);
+    esp8266Serial.printf("\"\r\n");
+    
+    getESP8266Response(3);
+    wait(1);
+    
+#endif    
+    
+    // connect wifi
+    pc.printf("\n---------- Wi-fi Connect ----------\r\n");
+    
+    esp8266Serial.printf("AT+CWJAP=\"");
+    esp8266Serial.printf(SSID);
+    esp8266Serial.printf("\",\"");
+    esp8266Serial.printf(PASSWORD);
+    esp8266Serial.printf("\"\r\n");
+    
+    getESP8266Response(3);
+    wait(2);
+    
+    // single connection
+    pc.printf("\n---------- Setting Connection Mode ----------\r\n");
+    
+    esp8266Serial.printf("AT+CIPMUX=0\r\n");
+    
+    getESP8266Response(1);
+    wait(1);
+    
+    // set UDP connection
+    pc.printf("\n---------- Setting UDP Connection ----------\r\n");
+    
+    esp8266Serial.printf("AT+CIPSTART=");
+    esp8266Serial.printf("\"UDP\",\"");
+    esp8266Serial.printf(REMOTE_ADDRESS);
+    esp8266Serial.printf("\",");
+    esp8266Serial.printf(REMOTE_PORT);
+    esp8266Serial.printf(",");
+    esp8266Serial.printf(LOCAL_PORT);
+    esp8266Serial.printf(",");
+    esp8266Serial.printf("0\r\n");
+    
+    getESP8266Response(3);
+    wait(1);
+
+    // set data transmission mode
+    pc.printf("\n---------- Setting Data Transmission Mode ----------\r\n");
+    
+    esp8266Serial.printf("AT+CIPMODE=1\r\n");
+    
+    getESP8266Response(1);
+    wait(1);
+    
+    // change Baud Rate 
+    pc.printf("\n---------- Change Baud Rate 4Mbps ----------\r\n");
+    
+    esp8266Serial.printf("AT+UART_CUR=4000000,8,1,0,0\r\n");
+    getESP8266Response(3);
+    
+    esp8266Serial.baud(4000000);
+    wait(1);
+    
+    // ready to send data
+    pc.printf("\n---------- Ready to Send Data ----------\r\n");
+    
+    esp8266Serial.printf("AT+CIPSEND\r\n");
+    
+    getESP8266Response(2);
+    wait(1);
+}
+
+//-------------------------------------------------------------
+// Main
+
+int main() {
+    
+    uint8_t i, idx;
+    uint8_t oscBuff[SEND_BUFF_SIZE] = {0};
+    static uint8_t scale;
+    uint8_t note[4] = {0};
+    static uint8_t _note[4];
+    uint16_t adc[4] = {0};
+    static uint16_t _adc[4];
+    float pot[2] = {0};
+    static float _pot[2] = {potPin1.read(), potPin2.read()};
+    
+    // Init SPI (2MHz clock)
+    spi.format(8, 0);
+    spi.frequency(2000000);
+    csPin = 1;
+    
+    // setup esp8266 wi-fi
+    esp8266Serial.baud(115200);
+    connectWifi();
+    
+    // start MIDI (ch1)
+    midi.begin(MIDI_CHANNEL);
+    
+    // start InterruptIn rising edge 
+    switch1.attach(&interruptSW1, IRQ_RISE, 10);
+    switch2.attach(&interruptSW2, IRQ_RISE, 10);
+    
+    // start timer (wait untile esp8266 transmission completed)
+    timer.start();
+    
+    while (1) {
+        
+        scale = map(scalePin.read_u16(), 0, 51890, 0, (SCALE_TOTAL - 1));
+
+        for (i = 0; i < 4; ++i) {
+            // read ADC
+            adc[i] = adcRead(i);
+
+            if (abs(adc[i] - _adc[i]) > 10) {
+                
+                changeFlag = true;
+                
+                switch (i) {
+                    case 0:
+                        bndl.add("/acv1").add(adc[i]);
+                        break;
+                    case 1:
+                        bndl.add("/acv2").add(adc[i]);
+                        break;
+                    case 2:
+                        bndl.add("/acv3").add(adc[i]);
+                        break;
+                    case 3:
+                        bndl.add("/acv4").add(adc[i]);
+                        break;
+                }
+            }
+            
+            if (abs(adc[i] - _adc[i]) > 31) {
+                
+                // MIDI quantize
+                switch (scale) {
+                    
+                    case Lin:
+                    case Chr:
+                        note[i] = map(adc[i], 825, 3757, 0, (84 - MAP_OFFSET)) + CALIB_OFFSET; // C0(12) ~ C7(96)
+                        break;
+                        
+                    case Maj:
+                        note[i] = calibMapMidi2[map(adc[i], 0, 4095, 0, QUAN_RES2 - 1)] + MIDI_OFFSET;
+                        break;
+                        
+                    case M7:
+                        note[i] = calibMapMidi3[map(adc[i], 0, 4095, 0, QUAN_RES3 - 1)] + MIDI_OFFSET;
+                        break;
+                        
+                    case Min7:
+                        note[i] = calibMapMidi4[map(adc[i], 0, 4095, 0, QUAN_RES4 - 1)] + MIDI_OFFSET;
+                        break;
+                        
+                    case Dor:
+                        note[i] = calibMapMidi5[map(adc[i], 0, 4095, 0, QUAN_RES5 - 1)] + MIDI_OFFSET;
+                        break;
+                        
+                    case Min:
+                        note[i] = calibMapMidi6[map(adc[i], 0, 4095, 0, QUAN_RES6 - 1)] + MIDI_OFFSET;
+                        break;
+                        
+                    case S5th:
+                        note[i] = calibMapMidi7[map(adc[i], 0, 4095, 0, QUAN_RES7 - 1)] + MIDI_OFFSET;
+                        break;
+                        
+                    case Wht:
+                        note[i] = calibMapMidi8[map(adc[i], 0, 4095, 0, QUAN_RES8 - 1)] + MIDI_OFFSET;
+                        break;
+                
+                }
+                    
+            
+                if (_note[i] != note[i]) {
+                    
+                    midi.sendNoteOff(_note[i], 0, MIDI_CHANNEL);
+                    midi.sendNoteOn(note[i], 100, MIDI_CHANNEL);
+                    
+                    _note[i] = note[i];
+                }
+                
+            }
+            
+            _adc[i] = adc[i];
+        }
+
+        // check potentiometer value
+        pot[0] = potPin1.read();
+        pot[1] = potPin2.read();
+
+        if (fabs(pot[0] - _pot[0]) > 0.02f) {
+
+            bndl.add("/pot1").add(pot[0] * 1023.0f);
+            midi.sendControlChange(0x16, map(potPin1.read_u16(), 0, 65535, 0, 127), MIDI_CHANNEL); // microKorg Noise Level
+
+            _pot[0] = pot[0];
+            changeFlag = true;
+        
+        } else if (fabs(pot[1] - _pot[1]) > 0.02f) {
+
+            bndl.add("/pot2").add(pot[1] * 1023.0f);
+            midi.sendControlChange(0x5E, map(potPin2.read_u16(), 0, 65535, 0, 127), MIDI_CHANNEL); // microKorg Delay Level
+
+            _pot[1] = pot[1];
+            changeFlag = true;
+        }
+        
+        if (changeFlag && timer.read_ms() > WAIT_SEND) {
+            
+            idx = 0;
+            int len = bndl.send(oscBuff);
+            
+            while (len--) {
+                // send OSC to esp8266 wifi
+                esp8266Serial.putc(oscBuff[idx++]);
+            }
+
+            changeFlag = false;
+            bndl.empty(); // empty the bundle to free room for a new one
+            
+            timer.reset();
+        }
+
+    }
+    
+}