OSC-CV Converter

Dependencies:   Bonjour OSCReceiver TextLCD mbed mbed-rpc BurstSPI DebouncedInterrupt FastIO MIDI OSC OSCtoCV ClockControl

OSC to CV Converter

http://gtbts.tumblr.com/post/125663817741/osc-to-cv-converter-ver2-mbed-osctocv

/media/uploads/casiotone401/tumblr_nsg7y4pkfg1qlle9fo1_540.png

Revision:
15:3e4bc47d6a39
Parent:
14:977f3c5a4b4e
Child:
16:1196b8c87bb7
--- a/main.cpp	Thu Oct 16 14:14:25 2014 +0000
+++ b/main.cpp	Sun Aug 02 10:01:07 2015 +0000
@@ -1,5 +1,7 @@
 //-------------------------------------------------------------
-//                  TI DAC8568  OSC-CV Converter
+//                  OSCtoCV Converter
+//   Schematic, touchOSC template & VST Plug-in 
+//   http://gtbts.tumblr.com/post/125663817741/osc-to-cv-converter-ver2-mbed-osctocv
 //
 //   DAC8568 16bit Octal DAC http://www.ti.com/product/dac8568
 //
@@ -14,6 +16,9 @@
 //   http://www.eleclabo.com/denshi/device/lcd1602/gcram.html
 //   Dirk-Willem van Gulik's BonjourLib
 //   http://mbed.org/users/dirkx/code/BonjourLib/file/bb6472f455e8/services/mDNS
+//   ADDAC System & sneak-thief's Euclidean Polyrhythm generator
+//   https://github.com/addacsystem/ADDAC-Library
+//   https://www.muffwiggler.com/forum/viewtopic.php?p=1451228#1451228
 //
 // Released under the MIT License: http://mbed.org/license/mit
 //-------------------------------------------------------------
@@ -22,12 +27,17 @@
 #pragma Otime
 
 #include "mbed.h"
+#include "FastIO.h"
+#include "DebouncedInterrupt.h"
+#include "BurstSPI.h"
 #include "TextLCD.h"       //edit "writeCommand" "writeData" protected -> public
 #include "EthernetNetIf.h"
 #include "HTTPServer.h"
 #include "mDNSResponder.h" // mDNS response to announce oneselve
 #include "UDPSocket.h"
 #include "OSCReceiver.h"
+#include "mbedOSC.h"
+#include "MIDI.h"
 #include <stdlib.h>
 #include <ctype.h>
 #include <math.h>
@@ -36,10 +46,12 @@
 // Define
 
 #define MODE_Calb           0        // Calibration (for VCO Tuning)
-#define MODE_LIN            1        // Linear LinearCV
-#define MODE_SEQ            2        // Mode Shift
-
-#define MODE_NUM            3        // Modes
+#define MODE_OSC            1        // Mode OSCtoCV 
+#define MODE_SEQ            2        // Mode Shift Sequencer
+#define MODE_185            3        // Mode M185 Sequencer
+#define MODE_EUC            4        // Mode Euclidean Sequencer 
+
+#define MODE_TOTAL          5        // Modes
 
 #define Lin                 0        // Linear LinearCV
 #define Chr                 1        // Chromatic
@@ -51,17 +63,20 @@
 #define S5th                7        // 5th
 #define Wht                 8        // Wholetone
 
-#define QUAN_RES1           115      // Quantize voltage Steps
-#define QUAN_RES2           67
-#define QUAN_RES3           39
-#define QUAN_RES4           48
-#define QUAN_RES5           67
-#define QUAN_RES6           67  
-#define QUAN_RES7           17
-#define QUAN_RES8           57
-
-#define SPI_RATE            20000000 // 20Mbps SPI Clock
-#define SCALING_N           38400.0
+#define SCALE_NUM           9        // Count Scale
+#define SCALE_AOUT          (65535 / SCALE_NUM - 1)
+
+#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 SPI_RATE            20000000 // 10Mbps SPI Clock
+#define SCALING_N           32256.0f
 #define INPUT_PORT          12345    // Input Port Number
 
 #define POLLING_INTERVAL    20       // Polling Interval (us)
@@ -80,6 +95,7 @@
 #define SETUP_INTERNAL_REF  0x08
 
 //------------------------------------------------------------- 
+// Gate Sequencer Macros
 
 #define _DISABLE            0
 #define _ENABLE             1
@@ -88,7 +104,17 @@
 #define GATE2               1
 #define GATE3               2
 #define GATE4               3
-#define GATEALL             4
+#define SUBGATE             4
+#define GATE_TOTAL          5
+
+#define INVERT              1
+#define NON_INVERT          0
+
+#define GATESOUT_ON         0
+#define GATESOUT_OFF        1
+
+#define SYNC_ON             0
+#define SYNC_OFF            1
 
 //------------------------------------------------------------- 
 // Beats (Note values)
@@ -97,174 +123,217 @@
 #define N2ND                2   // harf
 #define N4TH                4   // quarter
 #define N8TH                8
-#define N16TH               16
-#define N32TH               32
-#define N64TH               64
+#define N16TH              16
+#define N32TH              32
+#define N64TH              64
 #define NDOT2               3   // dotted
 #define NDOT4               7
 #define NDOT8               9
-#define NDOT16              11
-#define NDOT32              13
-#define TRIP2               15  // triplets
-#define TRIP4               17
-#define TRIP8               19
-#define TRIP16              21
-#define TRIP32              23
+#define NDOT16             11
+#define NDOT32             13
+#define TRIP2               3   // triplets
+#define TRIP4               6
+#define TRIP8              12
+#define TRIP16             24
+#define TRIP32             48
+#define SYNC24             96
 #define NRESET              0   // Gate Reset
 
+//------------------------------------------------------------- 
+// Sequencer Macros
+
+#define STEP_INDICATOR_ADDRESS "/seqstep/"   // touchOSC multi toggle(1x16(8)) for Current Step Indicator
+#define RESET_COUNTER_ADDRESS  "/reset"      // touchOSC label for Sequencer reset count                 
+
+//------------------------------------------------------------- 
+// M185 Macros
+
+#define PULSE_COUNT_ADDRESS    "/pulse"      // /pulse1 ~ pulse8        M185 Pulse Count
+#define GATE_MODE_ADDRESS      "/gatemode"   // /gatemode1 ~ gatemode8  M185 Gate Mode
+
+#define SINGLE              0
+#define MUTE                1
+#define MULTI               2
+#define HOLD                3
+
+//------------------------------------------------------------- 
+// Euclidean Sequencer Macros
+
+#define READ_DELAY         10 // for debouncing 
+#define MAXCHANNELS         4
+#define MAXSTEPS           16 // max step length
+#define TRIGGER_DURATION 2200
+
+#define DISPLAY_UPDATE   2000 // how long active channel display is shown
+#define MATRIX_ADDRESS   "/matrix/" // touchOSC multi toggle(9x16) OSC address
+
+
 //-------------------------------------------------------------
 // Functions
 
+void InitOSCCV(void);
 inline void NetPoll(void);
-void InitOSCCV(void);
+inline float MapFloat(float, float, float, float, float);
 inline void UpdateCV(int, int, const unsigned int*);
-inline void CalibCV(void);
-inline void SetSCV(void);
-inline void SeqCV(int);
-inline void Seq(void);
-inline int UpdateGate(int, int, int, int, bool);
-inline void UpdateSync(int, int, bool);
-void CheckModeSW(void);
-inline void CVMeter(int, const unsigned int*);
-void LCD();
+inline void CalibrationCV(void);
+inline void SetCV(void);
+inline void ShiftCVSeq(int, bool);
+inline void M185Seq(int, bool);
+inline void SendCtrlState(uint8_t, uint8_t, uint8_t);
+inline int GateSeq(int, int, int, int, bool, bool, bool);
+inline int CheckBPM(void);
+inline void CheckModeSW(void);
+inline void LCD();
+inline void UpdateCVMeter(int, const unsigned int*);
 void WriteCustomChar(unsigned char, unsigned char*);
 int  SetupEthNetIf(void);
 inline size_t strlength(const char *);
 inline void onUDPSocketEvent(UDPSocketEvent);
+void EuclideanSeq(int, bool, bool);
+unsigned int Euclid(int, int, int);
+inline int BitRead(uint16_t, int);
+uint16_t BitReadOffset(int, uint16_t, uint16_t); 
+unsigned int ConcatBin(unsigned int, unsigned int);
+void Sync(int, bool);
+int EncodeReadN(int);
+int EncodeReadK(int);
+int EncodeReadO(int);
+inline char * SetMatrixAddress(int, int, bool);
 
 //-------------------------------------------------------------
 // Silentway Calibration Data Mapping
 // http://www.expert-sleepers.co.uk/silentway.html
 
-// Chromatic Scale
+//  Chromatic Scale
 const float calibMap1[QUAN_RES1] = {
-0.00331362,   0.01097947,   0.01864531,   0.02631116,   0.03397701, 
-0.04164285,   0.04930869,   0.05697454,   0.06464039,   0.07230624, 
-0.07997208,   0.08763793,   0.09530377,   0.10296962,   0.11063547, 
-0.11830132,   0.12590303,   0.13306051,   0.14021800,   0.14737549, 
-0.15453300,   0.16169049,   0.16884798,   0.17600547,   0.18316296, 
-0.19032045,   0.19747795,   0.20463544,   0.21179293,   0.21895042, 
-0.22610791,   0.23326540,   0.24042290,   0.24758039,   0.25476459, 
-0.26196238,   0.26916021,   0.27635801,   0.28355584,   0.29075363, 
-0.29795146,   0.30514926,   0.31234708,   0.31954488,   0.32674271, 
-0.33394051,   0.34113833,   0.34833613,   0.35553396,   0.36273175, 
-0.36992958,   0.37713069,   0.38433966,   0.39154866,   0.39875764, 
-0.40596664,   0.41317561,   0.42038459,   0.42759359,   0.43480256, 
-0.44201156,   0.44922054,   0.45642951,   0.46363851,   0.47084749, 
-0.47805649,   0.48526546,   0.49247447,   0.49968344,   0.50694764, 
-0.51421440,   0.52148110,   0.52874786,   0.53601462,   0.54328132, 
-0.55054808,   0.55781484,   0.56508154,   0.57234830,   0.57961506, 
-0.58688176,   0.59414852,   0.60141528,   0.60868198,   0.61594874, 
-0.62321550,   0.63052768,   0.63785475,   0.64518178,   0.65250880, 
-0.65983582,   0.66716284,   0.67448992,   0.68181694,   0.68914396, 
-0.69647098,   0.70379800,   0.71112502,   0.71845210,   0.72577912, 
-0.73310614,   0.74043316,   0.74776018,   0.75861782,   0.77102989, 
-0.78344196,   0.79585397,   0.80826604,   0.82067811,   0.83309019, 
-0.84550226,   0.85791427,   0.87032634,   0.90296346,   0.94781560
+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] = {
-0.01097947,   0.02631116,   0.03397701,   0.04930869,   0.06464039,
-0.07997208,   0.08763793,   0.10296962,   0.11830132,   0.12590303,
-0.14021800,   0.15453300,   0.16884798,   0.17600547,   0.19032045,
-0.20463544,   0.21179293,   0.22610791,   0.24042290,   0.25476459,
-0.26196238,   0.27635801,   0.29075363,   0.29795146,   0.31234708,
-0.32674271,   0.34113833,   0.34833613,   0.36273175,   0.37713069,
-0.38433966,   0.39875764,   0.41317561,   0.42759359,   0.43480256,
-0.44922054,   0.46363851,   0.47084749,   0.48526546,   0.49968344,
-0.51421440,   0.52148110,   0.53601462,   0.55054808,   0.55781484,
-0.57234830,   0.58688176,   0.60141528,   0.60868198,   0.62321550,
-0.63785475,   0.64518178,   0.65983582,   0.67448992,   0.68914396,
-0.69647098,   0.71112502,   0.72577912,   0.73310614,   0.74776018,
-0.77102989,   0.79585397,   0.80826604,   0.83309019,   0.85791427,
-0.87032634,   0.94781560
+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] = {
-0.02631116,   0.04930869,   0.07997208,   0.08763793,   0.11830132,
-0.14021800,   0.16884798,   0.17600547,   0.20463544,   0.22610791,
-0.25476459,   0.26196238,   0.29075363,   0.31234708,   0.34113833,
-0.34833613,   0.37713069,   0.39875764,   0.42759359,   0.43480256,
-0.44922054,   0.46363851,   0.48526546,   0.51421440,   0.52148110,
-0.55054808,   0.57234830,   0.60141528,   0.60868198,   0.62321550,
-0.63785475,   0.65983582,   0.68914396,   0.69647098,   0.72577912,
-0.74776018,   0.79585397,   0.85791427,   0.94781560
+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] = {
-0.01097947,   0.01864531,   0.03397701,   0.04930869,   0.07230624,
-0.08763793,   0.11063547,   0.14021800,   0.16169049,   0.17600547,
-0.19747795,   0.22610791,   0.24042290,   0.24758039,   0.26196238,
-0.29075363,   0.31234708,   0.33394051,   0.34833613,   0.36273175,
-0.36992958,   0.38433966,   0.39875764,   0.41317561,   0.42038459,
-0.43480256,   0.45642951,   0.48526546,   0.50694764,   0.52148110,
-0.53601462,   0.55781484,   0.57234830,   0.59414852,   0.62321550,
-0.63052768,   0.64518178,   0.65983582,   0.68181694,   0.69647098,
-0.71845210,   0.74776018,   0.77102989,   0.78344196,   0.80826604,
-0.83309019,   0.84550226,   0.94781560
+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] = {
-0.01097947,   0.02631116,   0.04164285,    0.04930869,   0.06464039,
-0.07997208,   0.08763793,   0.10296962,    0.11830132,   0.13306051,
-0.14021800,   0.15453300,   0.16884798,    0.17600547,   0.19032045,
-0.20463544,   0.21895042,   0.22610791,    0.24042290,   0.25476459,
-0.26196238,   0.27635801,   0.29075363,    0.30514926,   0.31234708,
-0.32674271,   0.34113833,   0.34833613,    0.36273175,   0.37713069,
-0.39154866,   0.39875764,   0.41317561,    0.42759359,   0.43480256,
-0.44922054,   0.46363851,   0.47805649,    0.48526546,   0.49968344,
-0.51421440,   0.52148110,   0.53601462,    0.55054808,   0.56508154,
-0.57234830,   0.58688176,   0.60141528,    0.60868198,   0.62321550,
-0.63785475,   0.65250880,   0.65983582,    0.67448992,   0.68914396,
-0.69647098,   0.71112502,   0.72577912,    0.74043316,   0.74776018,
-0.77102989,   0.79585397,   0.80826604,    0.83309019,   0.85791427,
-0.90296346,   0.94781560
+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] = {
-0.01097947,   0.01864531,   0.03397701,   0.04930869,   0.05697454,
-0.07230624,   0.08763793,   0.10296962,   0.11063547,   0.12590303,
-0.14021800,   0.14737549,   0.16169049,   0.17600547,   0.19032045,
-0.19747795,   0.21179293,   0.22610791,   0.23326540,   0.24758039,
-0.26196238,   0.27635801,   0.28355584,   0.29795146,   0.31234708,
-0.31954488,   0.33394051,   0.34833613,   0.36273175,   0.36992958,
-0.38433966,   0.39875764,   0.40596664,   0.42038459,   0.43480256,
-0.44922054,   0.45642951,   0.47084749,   0.48526546,   0.49247447,
-0.50694764,   0.52148110,   0.53601462,   0.54328132,   0.55781484,
-0.57234830,   0.57961506,   0.59414852,   0.60868198,   0.62321550,
-0.63052768,   0.64518178,   0.65983582,   0.66716284,   0.68181694,
-0.69647098,   0.71112502,   0.71845210,   0.73310614,   0.74776018,
-0.75861782,   0.78344196,   0.80826604,   0.83309019,   0.84550226,
-0.87032634,   0.94781560
+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] = {
-0.01097947,  0.06464039,   0.11830132,    0.16884798,    0.21895042,
-0.26916021,  0.31954488,   0.36992958,    0.42038459,    0.47084749,
-0.52148110,  0.57234830,   0.62321550,    0.67448992,    0.72577912,
-0.79585397,  0.90296346
+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] = {
-0.01097947,   0.02631116,   0.04164285,   0.05697454,    0.07230624,
-0.08763793,   0.10296962,   0.11830132,   0.13306051,    0.14737549,
-0.16169049,   0.17600547,   0.19032045,   0.20463544,    0.21895042,
-0.23326540,   0.24758039,   0.26196238,   0.27635801,    0.29075363,
-0.30514926,   0.31954488,   0.33394051,   0.34833613,    0.36273175,
-0.37713069,   0.39154866,   0.40596664,   0.42038459,    0.43480256,
-0.44922054,   0.46363851,   0.47805649,   0.49247447,    0.50694764,
-0.52148110,   0.53601462,   0.55054808,   0.56508154,    0.57961506,
-0.59414852,   0.60868198,   0.62321550,   0.63785475,    0.65250880,
-0.66716284,   0.68181694,   0.69647098,   0.71112502,    0.72577912,
-0.74043316,   0.75861782,   0.78344196,   0.80826604,    0.83309019,
-0.85791427,   0.90296346
+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]
 };
 
 //-------------------------------------------------------------
@@ -283,52 +352,127 @@
 // Global Variables
 
 float   gOSC_cv[8];
-float   gSeq_cv1[8], gSeq_cv2[8];
+float   gSeq_cv[16];
 float   gGlide;
 int     gMode;
 
 // Variables for Control
-
-float gCtrl[6];
-bool gCtrlSW[6] = {false};
+/*
+gCtrl[0] /ctrl1 BPM
+gCtrl[1] /ctrl2 Quantize mode
+gCtrl[3] /ctrl4 Glide
+gCtrl[4] /ctrl5 M185 Reset Count
+
+gCtrlSW[0] /ctrlsw1 Sequencer STOP
+gCtrlSW[1] /ctrlsw2 Euclidean Sequencer reset
+gCtrlSW[2] /ctrlsw3 Sequencer Loop
+gCtrlSW[3] /ctrlsw4 Euclid Seq ON
+
+float gPulseCount[8] = {0};  M185 Pulse Count
+float gGateMode[8] = {0};    M185 Gate Mode
+float gSlide[8];             M185 Slide
+
+gEucA[0] /euca1 Euclidean Pattern length  (n) ch1
+gEucA[1] /euca2 Euclidean Pattern density (k) ch1
+gEucA[2] /euca3 Euclidean Pattern offset  (o) ch1
+gEucA[3] ~ [5] /euca4 ~ /euca6 Euclidean Pattern nko ch2
+gEucB[0] ~ [5] /eucb1 ~ /eucb6 Euclidean Pattern nko ch3 ~ ch4
+*/
+
+float gCtrl[8];
+bool  gCtrlSW[8] = {false};
+
+// Variables for Sequencer
+float gPulseCount[8] = {0};
+float gGateMode[16] = {0};
+float gSlide[16];
+
+// Euclidean SEQ Variables
+float gEucA[6], gEucB[6];
+int channels = MAXCHANNELS;
+unsigned int beat_holder[MAXCHANNELS];
+unsigned int channelbeats[MAXCHANNELS][5];
+
+bool pulses_active = false; // is active while a beat pulse is playing 
+bool lights_active = false;
+int pulse_length = TRIGGER_DURATION; //pulse length
+
+unsigned int last_read[MAXCHANNELS];
+unsigned int last_changed[MAXCHANNELS];
+unsigned int last_sync;
+
+unsigned int euc_time;
+
+// Variables for Arduino
+uint16_t gArdCV[4];
+uint16_t gArdCtrl[4];
+bool gArdSW[4] = {false};
 
 //-------------------------------------------------------------
 // mbed Functions
 
-TextLCD gLCD(p9, p10, p11, p12, p13, p14); // rs, e, d4-d7
-
-SPI         gSPI(p5,p6,p7);     // SPI (p6 unconnected)
-DigitalOut  gSYNCMODE(p15);     // SYNC DAC8568
-DigitalOut  gLDAC(p16);         // LDAC DAC8568
-
-DigitalOut  gGATES[4] = {p23, p24, p24, p25};   // GateOut
-DigitalOut  gLEDS[4] = {p18, p19, p20, p21};    // LED
-DigitalOut  gCLOCKOUT(p26);                     // ClockOut
-
-AnalogIn    gAIN(p17);  // Glide Potentiometer
-InterruptIn gSW(p30);   // Mode SW
-
-Timer       gTimer;     // Timer
-Ticker      gPoller;    // Ticker Polling
+TextLCD      gLCD(p9, p10, p11, p12, p13, p14); // rs, e, d4-d7
+
+BurstSPI     gSPI(p5,p6,p7);    // SPI (p6 unconnected)
+
+FastOut<p15> gSYNCMODE;         // SYNC DAC8568
+FastOut<p16> gLDAC;             // LDAC DAC8568
+
+DigitalOut   gGATES[4] = {p21, p22, p23, p24};   // GateOut
+FastOut<p19> gSUBGATE;                           // SubGateOut
+FastOut<p25> gCLOCKOUT;                          // ClockOut
+
+AnalogOut    gAOUT(p18);
+
+AnalogIn gAIN(p17);
+DebouncedInterrupt  gSW(p30);   // Mode SW
+
+// Serial for Arduino
+MIDI midi(p28, p27);
+
+Timer        gTimer;     // Timer
+Ticker       gPoller;    // Ticker for Polling
 
 // Ethernet
-EthernetNetIf   gEth;
+EthernetNetIf   gEth(
+                     IpAddr(192,168,1,6),
+                     IpAddr(255,255,255,0),
+                     IpAddr(192,168,1,1),
+                     IpAddr(192,168,1,1)
+                    );
+/* static ip
+EthernetNetIf   gEth(
+                     IpAddr(192,168,1,2),
+                     IpAddr(255,255,255,0),
+                     IpAddr(192,168,1,1),
+                     IpAddr(192,168,1,1)
+                    );
+*/
+                     
 UDPSocket       gUdp;
 
+// touchOSC Address
+uint8_t touchOSCAddress[] = { 192, 168, 1, 7 };
+int touchOSCPort = 9000;
+
+OSCClass osc;
+OSCMessage sendMes;
+
 //-------------------------------------------------------------
 // main
  
 int main() 
 { 
     float pot, _pot;
+    int bpm;
     
-//Clock Up 110Mhz -------------------------------------------------------------
+//Clock Up --------------------------------------------------------------------
     LPC_SC->PLL0CON   = 0x00;             /* PLL0 Disable                    */
     LPC_SC->PLL0FEED  = 0xAA;
     LPC_SC->PLL0FEED  = 0x55;
  
     LPC_SC->CCLKCFG   = 0x00000003;       /* Select Clock Divisor = 4        */
-    LPC_SC->PLL0CFG   = 0x00020037;       /* configure PLL0                  */
+    LPC_SC->PLL0CFG   = 0x00020038;       /* configure PLL0                  */
     LPC_SC->PLL0FEED  = 0xAA;             /* divide by 3 then multiply by 50 */
     LPC_SC->PLL0FEED  = 0x55;             /* PLL0 frequency = 400,000,000    */
  
@@ -344,18 +488,163 @@
     
     SystemCoreClockUpdate();
 //-----------------------------------------------------------------------------
-    
-    if(SetupEthNetIf() == -1)
+        
+    if (SetupEthNetIf() == -1)
     {
-        for(int i = 0; i < 4; i++) 
+        for (int i = 0; i < 4; ++i) 
         {
-            gLEDS[i] = 1;
+            gGATES[i] = true;
             wait(0.25);
         }
         
         return -1;
     }
     
+    InitOSCCV();
+    
+    gCtrl[3] = _pot = pot = gMode = 0;
+    gGlide = gAIN.read();
+        
+    LCD();
+    gLCD.locate( 0, 1 );
+    gLCD.printf("12345678 G>>%3.2f", gGlide);
+    
+// Main loop
+    while (1) 
+    {   
+        LCD(); // Check Text LCD
+        
+        pot = gAIN.read();  // Update glide value
+        
+        if (!pot) // when glide pot value == 0 
+        {         // use gCtrl[3] value
+            if (abs(gCtrl[3] - _pot) > 0.01f)
+            {
+                _pot = gGlide = gCtrl[3];
+            
+                gLCD.locate( 9, 1 );
+                gLCD.printf("G>>%3.2f", gGlide);
+            }
+        
+        } else if (abs(pot - _pot) > 0.01f) {
+            
+            _pot = gGlide =  gAIN.read();
+            
+            gLCD.locate( 9, 1 );
+            gLCD.printf("G>>%3.2f", gGlide);
+        }
+        
+        switch (gMode)
+        {               
+            case MODE_OSC: // OSCtoCV mode
+            
+                SetCV();
+                break;
+                
+            case MODE_SEQ: // Shift Sequencer mode
+            
+                bpm = CheckBPM();
+
+                ShiftCVSeq(GateSeq(bpm, N16TH, GATE1, 3, NON_INVERT, GATESOUT_OFF, SYNC_ON), gCtrlSW[0]);
+                GateSeq(bpm, N8TH, GATE2, 3, NON_INVERT, GATESOUT_ON, SYNC_OFF);
+                
+                if (gCtrlSW[3])
+                {
+                    EuclideanSeq(GateSeq(bpm, N16TH, SUBGATE, 1, NON_INVERT, GATESOUT_OFF, SYNC_OFF), gCtrlSW[0], GATESOUT_OFF);
+                }
+                break;
+                
+            case MODE_185: // M185 Sequencer mode
+            
+                bpm = CheckBPM();
+            
+                M185Seq(GateSeq(bpm, N16TH, GATE1, 3, NON_INVERT, GATESOUT_OFF, SYNC_ON), gCtrlSW[0]);
+                GateSeq(bpm, N8TH, GATE2, 3, NON_INVERT, GATESOUT_ON, SYNC_OFF);
+                
+                if (gCtrlSW[3])
+                {
+                    EuclideanSeq(GateSeq(bpm, N16TH, SUBGATE, 1, NON_INVERT, GATESOUT_OFF, SYNC_OFF), gCtrlSW[0], GATESOUT_OFF);
+                }
+                break;
+                
+            case MODE_EUC: // Euclidean Sequencer mode
+            
+                bpm = CheckBPM();
+                
+                ShiftCVSeq(GateSeq(bpm, N1ST, SUBGATE, 3, NON_INVERT, GATESOUT_OFF, SYNC_OFF), gCtrlSW[0]); 
+                EuclideanSeq(GateSeq(bpm, N16TH, GATE1, 1, NON_INVERT, GATESOUT_OFF, SYNC_OFF), gCtrlSW[0], GATESOUT_ON);
+                break;
+                
+            default:       // CV Calibration mode
+                
+                CalibrationCV(); 
+                break;
+        }
+        
+    }
+}
+
+//-------------------------------------------------------------
+// Initialize OSCtoCV
+
+void InitOSCCV()
+{
+    int i;
+// Write custom char LCD CGRAM
+    WriteCustomChar(0x00, str1);
+    WriteCustomChar(0x01, str2);
+    WriteCustomChar(0x02, str3);
+    WriteCustomChar(0x03, str4);
+    WriteCustomChar(0x04, str5);
+    WriteCustomChar(0x05, str6);
+    WriteCustomChar(0x06, str7);
+    WriteCustomChar(0x07, str8);
+    
+// Init  SPI
+    gLDAC = _ENABLE;
+    gSPI.format(8,1);           // Data word length 8bit, Mode=1
+    gSPI.frequency(SPI_RATE);
+    
+    UpdateCV(CLR, 0, 0);        // Ignore CLR Pin
+
+// Initialize Euclid Sequencer
+    channelbeats[0][0] = 16;
+    channelbeats[0][1] = 8;
+    channelbeats[0][2] = 0;
+    channelbeats[0][3] = 0;
+    
+    channelbeats[1][0] = 16;
+    channelbeats[1][1] = 9;
+    channelbeats[1][2] = 0;
+    channelbeats[1][3] = 0;
+    
+    channelbeats[2][0] = 16;
+    channelbeats[2][1] = 7;
+    channelbeats[2][2] = 0;
+    channelbeats[2][3] = 0;
+    
+    channelbeats[3][0] = 16;
+    channelbeats[3][1] = 9;
+    channelbeats[3][2] = 0;
+    channelbeats[3][3] = 0;
+
+    for (i = 0; i < channels; ++i) 
+    {
+        beat_holder[i] = Euclid(channelbeats[i][0], channelbeats[i][1], channelbeats[i][3]);
+    }
+    
+// Init BPM
+    gCtrl[0] = 0.398f;
+
+// Init Sequence Data
+    for (i = 0; i < 16; ++i) 
+    {
+        gSeq_cv[i] = calibMap1[69] * SCALING_N;
+    }
+    
+// Init M185 Reset Count    
+    gCtrl[4] = 1;
+
 // mdns (Bonjour)
     HTTPServer svr;
     mDNSResponder mdns;
@@ -364,57 +653,18 @@
     svr.bind(INPUT_PORT);
     IpAddr ip = gEth.getIp();
     mdns.announce(ip, "OSCtoCV", "_osc._udp", INPUT_PORT, "mbed(OSCtoCV)", (char *[]) {"path=/",NULL});
-    
-    InitOSCCV();
-    
-    _pot = pot = gMode = 0;
-    gGlide = gCtrl[3] = gAIN.read();
-        
-    LCD();
-    gLCD.locate( 0, 1 );
-    gLCD.printf("12345678 G>>%3.2f", gGlide);
+
+// Set OSC message for sending 
+    sendMes.setIp(touchOSCAddress); 
+    sendMes.setPort(touchOSCPort);
     
-// loop
-    while(1) 
-    {
-        pot = gAIN.read();  // Glide Value
-        
-        if(pot == 0) 
-        {
-            if(abs(gCtrl[3] - _pot) > 0.01f)
-            {
-                _pot = gGlide = gCtrl[3];
-            
-                gLCD.locate( 0, 1 );
-                gLCD.printf("12345678 G>>%3.2f", gGlide);
-            }
-        
-        } else if (abs(pot - _pot) > 0.01f) {
-            
-            gGlide = _pot = gAIN.read();
-            
-            gLCD.locate( 0, 1 );
-            gLCD.printf("12345678 G>>%3.2f", gGlide);
-        }
-        
-        switch(gMode)
-        {               
-            case MODE_LIN:
-            
-                SetSCV();
-                break;
-                
-            case MODE_SEQ:
-        
-                Seq();
-                break;
-                
-            default:
-                
-                CalibCV();
-                break;
-        }
-    }
+    gSW.attach(&CheckModeSW,IRQ_RISE, 30);     // InterruptIn rising edge(ModeSW)
+    gPoller.attach_us(&NetPoll, POLLING_INTERVAL);  // Ticker Polling
+    
+    wait(0.4);
+
+    // Begin Serial for Arduino
+    //ardSerial.baud(115200);
 }
 
 //-------------------------------------------------------------
@@ -426,34 +676,11 @@
 }
 
 //-------------------------------------------------------------
-// Initialize OSC-CV
-
-void InitOSCCV()
+// Map Function 
+
+inline float MapFloat(float x, float in_min, float in_max, float out_min, float out_max)
 {
-// write custom char LCD CGRAM
-    WriteCustomChar(0x00, str1);
-    WriteCustomChar(0x01, str2);
-    WriteCustomChar(0x02, str3);
-    WriteCustomChar(0x03, str4);
-    WriteCustomChar(0x04, str5);
-    WriteCustomChar(0x05, str6);
-    WriteCustomChar(0x06, str7);
-    WriteCustomChar(0x07, str8);
-    
-// Init. SPI
-    gLDAC = _ENABLE;
-    gSPI.format(8,1);           // Data word length 8bit, Mode=1
-    gSPI.frequency(SPI_RATE);
-    
-    UpdateCV(CLR, 0, 0);        // Ignore CLR Pin
-    
-    gSW.mode(PullUp);           // Use internal pullup for ModeSW
-    wait(.001);
-    
-    gSW.rise(&CheckModeSW);     // InterruptIn rising edge(ModeSW)
-    gPoller.attach_us(&NetPoll, POLLING_INTERVAL);  // Ticker Polling
-    
-    wait(0.2);
+  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
 }
 
 //-------------------------------------------------------------
@@ -462,9 +689,8 @@
 
 inline void UpdateCV(int control, int address, const unsigned int *data)
 {
-    __disable_irq();
-    
-    switch(control)
+
+    switch (control)
     {
         case WRITE_UPDATE_N:
 
@@ -476,6 +702,7 @@
             gSYNCMODE = _ENABLE;
             gLDAC = _DISABLE;
             gLDAC = _ENABLE;
+            
             break;
 
         case RESET:
@@ -486,6 +713,7 @@
             gSPI.write(00000000);
             gSPI.write(00000000);
             gSYNCMODE = _ENABLE;
+            
             break;
 
         case CLR:
@@ -496,52 +724,54 @@
             gSPI.write(00000000);
             gSPI.write(00000011);   // Ignore CLR Pin
             gSYNCMODE = _ENABLE;
+            
             break;
     }
-    
-    __enable_irq();
 }
 
 //-------------------------------------------------------------
-// Calibrate Mode
-
-inline void CalibCV()
+// Calibration Mode
+
+inline void CalibrationCV()
 {
     static int ch;
     unsigned int cv;
 
-    switch(gMode) 
+    switch (gMode) 
         {
             case MODE_Calb:
                 
-                cv = (unsigned int)((calibMap1[68] + 0.0007) * SCALING_N);    // A880.0Hz
+                cv = (unsigned int)(calibMap1[69] * SCALING_N);  // A880.0Hz
                 
-                gGATES[0] = gGATES[1] = gGATES[2] = gGATES[3] = 1;
-                gLEDS[0] = gLEDS[1] = gLEDS[2] = gLEDS[3] = 1;
+                gSUBGATE = gGATES[0] = gGATES[1] = gGATES[2] = gGATES[3] = true;
                 
                 UpdateCV(WRITE_UPDATE_N, ch, &cv);
+                
                 break;
         }
 
-        CVMeter(ch, &cv);
+        UpdateCVMeter(ch, &cv);
         
-        ch++;
+        ++ch;
         ch &= 0x07;
 }
 
 //-------------------------------------------------------------
 // Calculate CV
 
-inline void SetSCV()
+inline void SetCV()
 {
-    static int ch, quan, mode, mcount;
+    static int ch, qmode, amode, mcount;
     static float glidecv[8];
     unsigned int cv;
     static float qcv;
 
-    mode = (gCtrl[1] * 8);
-
-    switch(mode) 
+    qmode = (gCtrl[1] * (SCALE_NUM - 1));
+    amode = SCALE_AOUT * qmode;
+    
+    gAOUT.write_u16(amode);
+
+    switch (qmode) 
         {
             case Lin:
                 
@@ -549,402 +779,697 @@
                 cv = (unsigned int)glidecv[ch];
                     
                 UpdateCV(WRITE_UPDATE_N, ch, &cv);
+
                 break;
                     
             case Chr:
-            
-                quan = (40616 / QUAN_RES1);
-                qcv = calibMap1[(unsigned int)(gOSC_cv[ch] / quan)];
-                    
-                glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
-                cv = (unsigned int)glidecv[ch];
-                        
-                UpdateCV(WRITE_UPDATE_N, ch, &cv);
-                break;
-                
-            case Maj:
-                
-                quan = (40616 / QUAN_RES2);
-                qcv = calibMap2[(unsigned int)(gOSC_cv[ch] / quan)];
-                    
-                glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
-                cv = (unsigned int)glidecv[ch];
-                        
-                UpdateCV(WRITE_UPDATE_N, ch, &cv);
-                break;
-            
-            case M7:
-            
-                quan = (40616 / QUAN_RES3);
-                qcv = calibMap3[(unsigned int)(gOSC_cv[ch] / quan)];
+
+                qcv = calibMap1[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES1 - 1))];
                     
                 glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
                 cv = (unsigned int)glidecv[ch];
                         
                 UpdateCV(WRITE_UPDATE_N, ch, &cv);
+
                 break;
                 
-            case Min7:
-                
-                quan = (40616 / QUAN_RES4);
-                qcv = calibMap4[(unsigned int)(gOSC_cv[ch] / quan)];
-                    
-                glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
-                cv = (unsigned int)glidecv[ch];
-                        
-                UpdateCV(WRITE_UPDATE_N, ch, &cv);
-                break;
-                    
-            case Dor:
-                
-                quan = (40616 / QUAN_RES5);
-                qcv = calibMap5[(unsigned int)(gOSC_cv[ch] / quan)];
-                    
+            case Maj:
+
+                qcv = calibMap2[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES2 - 1))];
+
                 glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
                 cv = (unsigned int)glidecv[ch];
-                        
+                                        
                 UpdateCV(WRITE_UPDATE_N, ch, &cv);
+
                 break;
-        
-            case Min:
-                
-                quan = (40616 / QUAN_RES6);
-                qcv = calibMap6[(unsigned int)(gOSC_cv[ch] / quan)];
-                    
-                glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
-                cv = (unsigned int)glidecv[ch];
-                        
-                UpdateCV(WRITE_UPDATE_N, ch, &cv);
-                break;
+            
+            case M7:
                 
-            case S5th:
-                
-                quan = (40616 / QUAN_RES7);
-                qcv = calibMap7[(unsigned int)(gOSC_cv[ch] / quan)];
-                    
-                glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
-                cv = (unsigned int)glidecv[ch];
-                        
-                UpdateCV(WRITE_UPDATE_N, ch, &cv);
-                break;
-                
-            case Wht:
-                
-                quan = (40616 / QUAN_RES8);
-                qcv = calibMap8[(unsigned int)(gOSC_cv[ch] / quan)];
+                qcv = calibMap3[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES3 - 1))];
                     
                 glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
                 cv = (unsigned int)glidecv[ch];
                         
                 UpdateCV(WRITE_UPDATE_N, ch, &cv);
+
+                break;
+                
+            case Min7:
+
+                qcv = calibMap4[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES4 - 1))];
+
+                glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv);
+
+                break;
+                    
+            case Dor:
+                
+                qcv = calibMap5[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES5 - 1))];
+
+                glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv);
+
+                break;
+        
+            case Min:
+                
+                qcv = calibMap6[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES6 - 1))];
+
+                glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv);
+
+                break;
+                
+            case S5th:
+
+                qcv = calibMap7[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES7 - 1))];
+
+                glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv);
+
+                break;
+                
+            case Wht:
+                
+                qcv = calibMap8[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES8 - 1))];
+
+                glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv);
+
                 break;
         }
 
-        if(mcount % 16 == 0) 
+        if (mcount == 0x1F) 
         {
-            CVMeter(ch, &cv);
+            UpdateCVMeter(ch, &cv);
         }
 
-        ch++;
+        ++ch;
         
-        if(ch &= 0x07)
+        if (ch &= 0x07)
         {
-            mcount ++;
+            ++mcount;
             mcount &= 0x3F;
         }
-        
 }
 
 //-------------------------------------------------------------
 // Sequence & Shift Out CV
 
-inline void SeqCV(int shift)
+inline void ShiftCVSeq(int trigger, bool reset)
 {
     int i, j;
-    static int ch, quan, mode;
+    static bool triggerState = false;
+    static bool stepFoward = false;
+    static bool _reset = false;
+    static uint8_t currentStep;
+    static int _resetCount, resetCount;
+    static uint8_t gateMode;
+    static uint8_t _gateMode[16];
+    static uint8_t ch, qmode, amode;
     static float glidecv[8], shiftcv[8];
     unsigned int cv;
     static float qcv;
         
-    mode = (gCtrl[1] * 8);  // Sequencer Quantize Mode (gCtrl[1])
+    qmode = (gCtrl[1] * (SCALE_NUM - 1.0f));  // Sequencer Quantize Mode (gCtrl[1])
+    amode = SCALE_AOUT * qmode;
     
-    switch(mode) 
+    gAOUT.write_u16(amode);
+    
+    switch (qmode) 
         {
             case Lin:
-            
-                if(ch < 8)
-                {
-                    glidecv[0] = glidecv[0] * gGlide + gSeq_cv1[ch] * (1.0f - gGlide);
-                            
-                } else {
-                        
-                    glidecv[0] = glidecv[0] * gGlide + gSeq_cv2[ch-8] * (1.0f - gGlide);
-                }
-                
+
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + gSeq_cv[currentStep] * (1.0f - gSlide[currentStep]);
+
+                cv = (unsigned int)glidecv[0];
+
+                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
+                break;
+    
+            case Chr:
+
+                qcv = calibMap1[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES1 - 1))];
+    
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
                 cv = (unsigned int)glidecv[0];
-                
+
                 UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
+                break;
+
+            case Maj:
+
+                qcv = calibMap2[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES2 - 1))];
+    
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
+                cv = (unsigned int)glidecv[0];
+
+                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
                 break;
-                    
-            case Chr:
+
+            case M7:
+
+                qcv = calibMap3[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES3 - 1))];
+    
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
+                cv = (unsigned int)glidecv[0];
+
+                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
+                break;
+    
+            case Min7:
+
+                qcv = calibMap4[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES4 - 1))];
             
-                quan = 40616 / QUAN_RES1;
-                
-                if(ch < 8)
-                {
-                    qcv = calibMap1[(unsigned int)(gSeq_cv1[ch] / quan)];
-                            
-                } else {
-                        
-                    qcv = calibMap1[(unsigned int)(gSeq_cv2[ch-8] / quan)];
-                }
-                    
-                glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
                 cv = (unsigned int)glidecv[0];
-                
+
                 UpdateCV(WRITE_UPDATE_N, 0, &cv);
-                break;
-                
-            case Maj:
-                
-                quan = 40616 / QUAN_RES2;
-                
-                if(ch < 8)
-                {
-                    qcv = calibMap2[(unsigned int)(gSeq_cv1[ch] / quan)];
-                            
-                } else {
-                        
-                    qcv = calibMap2[(unsigned int)(gSeq_cv2[ch-8] / quan)];
-                }
-                    
-                glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
-                cv = (unsigned int)glidecv[0];
-                
-                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
                 break;
             
-            case M7:
-                
-                quan = 40616 / QUAN_RES3;
-                
-                if(ch < 8)
-                {
-                    qcv = calibMap3[(unsigned int)(gSeq_cv1[ch] / quan)];
-                            
-                } else {
-                        
-                    qcv = calibMap3[(unsigned int)(gSeq_cv2[ch-8] / quan)];
-                }
-                    
-                glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+            case Dor:
+
+                qcv = calibMap5[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES5 - 1))];
+
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
                 cv = (unsigned int)glidecv[0];
-                
+
                 UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
                 break;
-                    
-            case Min7:
-                
-                quan = 40616 / QUAN_RES4;
-                
-                if(ch < 8)
-                {
-                    qcv = calibMap4[(unsigned int)(gSeq_cv1[ch] / quan)];
-                            
-                } else {
-                        
-                    qcv = calibMap4[(unsigned int)(gSeq_cv2[ch-8] / quan)];
-                }
-                
-                glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+
+            case Min:
+
+                qcv = calibMap6[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES6 - 1))];
+
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
                 cv = (unsigned int)glidecv[0];
-                
+
                 UpdateCV(WRITE_UPDATE_N, 0, &cv);
-                break;
-                            
-            case Dor:
-                
-                quan = 40616 / QUAN_RES5;
-                
-                if(ch < 8)
-                {
-                    qcv = calibMap5[(unsigned int)(gSeq_cv1[ch] / quan)];
-                            
-                } else {
-                        
-                    qcv = calibMap5[(unsigned int)(gSeq_cv2[ch-8] / quan)];
-                }
-                
-                glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
-                cv = (unsigned int)glidecv[0];
-                
-                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
                 break;
-                
-            case Min:
-                
-                quan = 40616 / QUAN_RES6;
-                
-                if(ch < 8)
-                {
-                    qcv = calibMap6[(unsigned int)(gSeq_cv1[ch] / quan)];
-                            
-                } else {
-                        
-                    qcv = calibMap6[(unsigned int)(gSeq_cv2[ch-8] / quan)];
-                }
-                
-                glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
-                cv = (unsigned int)glidecv[0];
-                
-                UpdateCV(WRITE_UPDATE_N, 0, &cv);
-                break;
-            
+
             case S5th:
-                
-                quan = 40616 / QUAN_RES7;
-                
-                if(ch < 8)
-                {
-                    qcv = calibMap7[(unsigned int)(gSeq_cv1[ch] / quan)];
-                            
-                } else {
-                        
-                    qcv = calibMap7[(unsigned int)(gSeq_cv2[ch-8] / quan)];
-                }
-                
-                glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+
+                qcv = calibMap7[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES7 - 1))];
+
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
                 cv = (unsigned int)glidecv[0];
-                
+
                 UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
                 break;
-                
+
             case Wht:
-                
-                quan = 40616 / QUAN_RES8;
-                
-                if(ch < 8)
-                {
-                    qcv = calibMap8[(unsigned int)(gSeq_cv1[ch] / quan)];
-                            
-                } else {
-                        
-                    qcv = calibMap8[(unsigned int)(gSeq_cv2[ch-8] / quan)];
-                }
-                    
-                glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+
+                qcv = calibMap8[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES8 - 1))];
+    
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
                 cv = (unsigned int)glidecv[0];
-                
+
                 UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
                 break;
         }
-            
-        for(i = 1; i < 8; ++i)
+    
+    for (i = 1; i < 8; ++i)
+    {
+        glidecv[i] = glidecv[i] * gSlide[currentStep] + shiftcv[i] * (1.0f - gSlide[currentStep]);
+        cv = (unsigned int)glidecv[i];
+
+        UpdateCV(WRITE_UPDATE_N, i, &cv);
+    }   
+        
+    if (trigger && !triggerState) // trigger ON
+    {        
+        stepFoward = triggerState = true;
+        
+    } else if (!trigger) { // trigger OFF
+        
+        if (gateMode != HOLD) 
         {
-            glidecv[i] = glidecv[i] * gGlide + shiftcv[i] * (1.0f - gGlide);
-            cv = (unsigned int)glidecv[i];
-                
-            UpdateCV(WRITE_UPDATE_N, i, &cv);
+            gGATES[0] = false;
         }
         
-        if(shift == 1)                  // GATE1
+        triggerState = false;
+    }
+    
+// check & update touchOSC ctrl parameter              
+    if (_gateMode[ch] != (gGateMode[ch] * 3))
+    {
+        _gateMode[ch] = (gGateMode[ch] * 3);
+            
+        if (_gateMode[ch] == MULTI)
         {
-            for(j = 1; j < 8; ++j)      // Shift ch2~8
+            _gateMode[ch] = HOLD;
+        }
+        
+        SendCtrlState(ch, _gateMode[ch], 8);
+    }
+    
+    if (reset && !_reset) // Stop & Reset
+    {
+        sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false));
+        sendMes.setArgs("i", 0);
+        osc.sendOsc(&sendMes);
+        
+        currentStep = 0;
+
+        sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false));
+        sendMes.setArgs("i", 1);
+        osc.sendOsc(&sendMes);
+        
+        _reset = true;
+
+    } else if (!reset) {
+
+        _reset = false;
+    }
+    
+    if (stepFoward)
+    {
+        if (gateMode != HOLD) // shift CV
+        {
+            for (j = 1; j < 8; ++j)
             {
                 shiftcv[j] = glidecv[j-1];
             }
+        }
+   
+        sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false));
+        sendMes.setArgs("i", 0);
+        osc.sendOsc(&sendMes);
+                    
+        ++currentStep;
+
+        if (gCtrlSW[2]) 
+        {
+            resetCount = 3;
+            
+        } else {
+            
+            resetCount = gCtrl[4] * 15;
+        }
         
-            ch++;
-            ch &= 0x0F;
+        if (_resetCount != resetCount)
+        {
+            sendMes.setTopAddress(RESET_COUNTER_ADDRESS);
+            sendMes.setArgs("i", (resetCount + 1));
+            osc.sendOsc(&sendMes);
+        }
+        
+        if (currentStep > resetCount)  // reset
+        {
+            currentStep = 0;
         }
         
-     
-        if(ch < 8)
+        sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false));
+        sendMes.setArgs("i", 1);
+        osc.sendOsc(&sendMes);
+                    
+        if (currentStep < 8)
         {
-            CVMeter(ch, &cv);
-                            
+            UpdateCVMeter(currentStep, &cv);
+                    
         } else {
-                        
-            CVMeter((ch-8), &cv);
+                
+            UpdateCVMeter((currentStep - 8), &cv);
+        }
+        
+        gateMode = (gGateMode[currentStep] * 3);
+    
+        if (gateMode == MULTI) // omit MULTI mode
+        {
+            gateMode = HOLD;
         }
-
+        
+        if (gateMode != MUTE) 
+        {
+            gGATES[0] = true;
+        }
+        
+        stepFoward = false;
+    }
+    
+    ++ch;
+    ch &= 0x0F;
 }
 
 //-------------------------------------------------------------
-// Sequencer Mode
-
-inline void Seq()
+// M185 Sequencer
+
+inline void M185Seq(int trigger, bool reset)
 {
-    static int bpm, _bpm;
+    int i, j;
+    static bool triggerState = false;
+    static bool stepFoward = false;
+    static bool _reset = false;
+    static uint8_t currentStep;
+    static int stepCount;
+    static int _resetCount, resetCount;
+    static uint8_t gateMode;
+    static uint8_t _gateMode[8];
+    static uint8_t _pulseCount[8];
+    static uint8_t ch, qmode, amode;
+    static float glidecv[8], shiftcv[8];
+    unsigned int cv;
+    static float qcv;
+    
+    qmode = (gCtrl[1] * (SCALE_NUM - 1));  // Sequencer Quantize Mode (gCtrl[1])
+    amode = SCALE_AOUT * qmode;
+    
+    gAOUT.write_u16(amode);
+    
+    switch (qmode) 
+        {
+            case Lin:
+
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + gSeq_cv[currentStep] * (1.0f - gSlide[currentStep]);
+
+                cv = (unsigned int)glidecv[0];
+
+                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
+                break;
+    
+            case Chr:
+
+                qcv = calibMap1[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES1 - 1))];
+    
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
+                cv = (unsigned int)glidecv[0];
+
+                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
+                break;
+
+            case Maj:
+
+                qcv = calibMap2[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES2 - 1))];
+    
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
+                cv = (unsigned int)glidecv[0];
+
+                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
+                break;
+
+            case M7:
+
+                qcv = calibMap3[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES3 - 1))];
     
-    bpm = (gCtrl[0] * 300 + 10);                    // Set BPM (gCtrl[0])
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
+                cv = (unsigned int)glidecv[0];
+
+                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
+                break;
+    
+            case Min7:
+
+                qcv = calibMap4[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES4 - 1))];
+            
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
+                cv = (unsigned int)glidecv[0];
+
+                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
+                break;
             
-    if(abs(bpm - _bpm) > 1)
+            case Dor:
+
+                qcv = calibMap5[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES5 - 1))];
+
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
+                cv = (unsigned int)glidecv[0];
+
+                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
+                break;
+
+            case Min:
+
+                qcv = calibMap6[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES6 - 1))];
+
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
+                cv = (unsigned int)glidecv[0];
+
+                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
+                break;
+
+            case S5th:
+
+                qcv = calibMap7[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES7 - 1))];
+
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
+                cv = (unsigned int)glidecv[0];
+
+                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
+                break;
+
+            case Wht:
+
+                qcv = calibMap8[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES8 - 1))];
+    
+                glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]);
+                cv = (unsigned int)glidecv[0];
+
+                UpdateCV(WRITE_UPDATE_N, 0, &cv);
+
+                break;
+        }
+    
+    for (i = 1; i < 8; ++i)
     {
-        UpdateGate(bpm, NRESET, GATEALL, 3, false); // Reset (if bpm change)
-        _bpm = bpm;
-                    
-    } else if (gCtrlSW[0]) {                        // Stop (gCtrlSW[0])
-                        
-        bpm = 0;
-    }
-            
-    if(!gCtrlSW[2] && !gCtrlSW[3])                  // Sequencer Mode1
-    {
-        SeqCV((UpdateGate(bpm, N16TH, GATE1, 3, false)));   // Shift Timming 16th note
-        UpdateGate(bpm, N8TH, GATE2, 3, 0);
-        UpdateGate(bpm, NDOT8, GATE3, 3, 0);
-        UpdateGate(bpm, TRIP4, GATE4, 3, 0);            
+        glidecv[i] = glidecv[i] * gSlide[currentStep] + shiftcv[i] * (1.0f - gSlide[currentStep]);
+        cv = (unsigned int)glidecv[i];
+
+        UpdateCV(WRITE_UPDATE_N, i, &cv);
     }
     
+    if (trigger && !triggerState) // trigger ON
+    {
+        if (gateMode == MULTI) 
+        {
+            gGATES[0] = true;
+            
+            sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false));
+            sendMes.setArgs("i", 1);
+            osc.sendOsc(&sendMes);
+        }
+        
+        stepFoward = triggerState = true;
+        
+    } else if (!trigger) { // trigger OFF
+
+        if (gateMode != HOLD) 
+        {
+            gGATES[0] = false;
+        } 
+        
+        if (gateMode == MULTI)
+        {
+            sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false));
+            sendMes.setArgs("i", 0);
+            osc.sendOsc(&sendMes);
+        }
+        
+        triggerState = false;
+    }
+
+// check & update touchOSC ctrl parameter        
+    if (_gateMode[ch] != gGateMode[ch] * 3 || _pulseCount[ch] != gPulseCount[ch] * 7)
+    {
+        _gateMode[ch] = (gGateMode[ch] * 3);
+        _pulseCount[ch] = (gPulseCount[ch] * 7);
+        
+        SendCtrlState(ch, _gateMode[ch], _pulseCount[ch]);
+    }
+    
+    if (reset && !_reset) // Stop & Reset
+    {
+        sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false));
+        sendMes.setArgs("i", 0);
+        osc.sendOsc(&sendMes);
+        
+        currentStep = 0;
+
+        sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false));
+        sendMes.setArgs("i", 1);
+        osc.sendOsc(&sendMes);
+        
+        _reset = true;
+
+    } else if (!reset) {
+
+        _reset = false;
+    }
+    
+    if (stepFoward)
+    {
+        if (gateMode != HOLD) // shift CV
+        {
+            for (j = 1; j < 8; ++j) 
+            {
+                shiftcv[j] = glidecv[j-1];
+            }
+        }
+        
+        --stepCount;
+                
+        if (stepCount == -1)
+        {            
+            sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false));
+            sendMes.setArgs("i", 0);
+            osc.sendOsc(&sendMes); 
+            
+            ++currentStep;
+            
+            if (gCtrlSW[2]) 
+            {
+                resetCount = 3;
+            
+            } else {
+            
+                resetCount = gCtrl[4] * 7;
+            }
+        
+            if (_resetCount != resetCount)
+            {
+                sendMes.setTopAddress(RESET_COUNTER_ADDRESS);
+                sendMes.setArgs("i", (resetCount + 1));
+                osc.sendOsc(&sendMes);
+            }
+
+            if (currentStep > resetCount) // reset
+            {
+                currentStep = 0;
+            }
+        
+            sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false));
+            sendMes.setArgs("i", 1);
+            osc.sendOsc(&sendMes);
+                    
+            UpdateCVMeter(currentStep, &cv);
+            
+        // check Pulse Count & Gate Mode
+            stepCount = (gPulseCount[currentStep] * 7);
+        
+            gateMode = (gGateMode[currentStep] * 3);
+            
+            if (gateMode != MUTE)
+            {
+                gGATES[0] = true;
+            }
+            
+        }
+                
+        stepFoward = false;
+    }
+        
+    ++ch;
+    ch &= 0x07;
 }
 
 //-------------------------------------------------------------
-// Check SW
-
-void CheckModeSW()
-{   
-    wait(0.05);
+// Send M185 Sequencer Status to touchOSC
+
+inline void SendCtrlState(uint8_t step, uint8_t gateMode, uint8_t stepCount)
+{
+    char pulseAddress[10] = PULSE_COUNT_ADDRESS;
+    char gateModeAddress[10] = GATE_MODE_ADDRESS;
+    char currentStep[2];
     
-    if(gMode < MODE_NUM - 1) 
-    {   
-        gMode++;
-            
-    } else {
-                
-        gMode = 0;
+    sprintf(currentStep, "%d", step + 1);
+    
+    strcat(gateModeAddress, currentStep);
+    
+    if(stepCount != 8) 
+    {
+        strcat(pulseAddress, currentStep);
+        sendMes.setTopAddress(pulseAddress);
+        sendMes.setArgs("i", (stepCount + 1));
+        osc.sendOsc(&sendMes);
     }
-    
-    gCLOCKOUT = gGATES[0] = gGATES[1] = gGATES[2] = gGATES[3] = 0;
-    gLEDS[0] = gLEDS[1] = gLEDS[2] = gLEDS[3] = 0;
-    
-    if(gMode == MODE_SEQ)
-    {
-        gTimer.start();     // Sequencer Timer Start
+
+    sendMes.setTopAddress(gateModeAddress);
         
-    } else {
+    switch (gateMode)
+        {
+            case SINGLE:
+            
+                sendMes.setArgs("s", "|");
+                
+                break;
+
+            case MUTE:
             
-        gTimer.stop();      // Sequencer Timer Stop
-    }
-    
-    LCD();
+                sendMes.setArgs("s", "O");
+                
+                break;
+
+            case MULTI:
+
+                sendMes.setArgs("s", "||");
+                
+                break;
+
+            case HOLD:
+                
+                sendMes.setArgs("s", "|-");
+                
+                break;
+        }
+
+        osc.sendOsc(&sendMes);
 }
 
 //-------------------------------------------------------------
-// GateOutSequence  beat(Note values) length(Gate time) invert(invert Gate)
-
-inline int UpdateGate(int bpm, int beat, int ch, int length, bool invert)
+// Gate Sequencer  beat(Note values) length(Gate time) invert(invert Gate)
+
+inline int GateSeq(int bpm, int beat, int ch, int length, bool invert, bool gatesoff, bool syncoff)
 {
     int i;
-    static int gatetime[4], oldgatetime[4];
-    static int bar, sync24, oldsynctime;
+    static int gatetime[GATE_TOTAL], oldgatetime[GATE_TOTAL];
+    static int _bpm, bar, sync24, oldsynctime;
     
     int time = gTimer.read_us();
     
-    bar = (60.0f / bpm) * 4000000;
-    sync24 = (bar / 4) / 24; // sync24 not tested
+    if (_bpm != bpm)
+    {
+        if (!bpm)
+        {
+            beat = NRESET;
+
+        } else {
+
+            bar = (60.0f / bpm) * 4000000;
+            //sync24 = (bar / 4) / 24; // sync24 not tested
+            
+            _bpm = bpm;
+        }
+    }
     
-    switch(beat)                                // Calculate Note values 
+    switch (beat) // Calculate Note values 
         {
             case NDOT2:
                 
@@ -972,58 +1497,100 @@
                 break;
                 
             case NRESET:
+            
+                gTimer.reset();
                 
-                for(i = 0; i < GATEALL; ++i)    // Reset
+                for (i = 0; i < GATE_TOTAL; ++i)    // Reset
                 {
-                    gTimer.reset();
                     oldsynctime = oldgatetime[i] = gatetime[i] = NRESET;
                 }
-                break;
-                
+
+                return 0;
+
             default:
                 
                 gatetime[ch] = bar / beat;
+                sync24 = bar / 16;
+                break;
         }
         
-        if(time > oldsynctime + sync24)  // sync24 not tested
+    if (time > oldsynctime + sync24)  // sync24 not tested
+    {
+        if (!syncoff) 
         {
             oldsynctime = time;
-            gCLOCKOUT = 1;
+            gCLOCKOUT = true;
             
-        } else if (time > sync24 - (sync24 - 2)) {
+            midi.sendRealTime(Clock); // MIDI Clock
+        }
         
-            gCLOCKOUT = 0;
+    } else if (time > oldsynctime - (sync24 - 2)) {
+
+        if (!syncoff) 
+        {
+            gCLOCKOUT = false;
         }
-    
-    if (ch == GATEALL) 
+    }
+
+    if (ch == GATE_TOTAL) 
     {
         return -1;
         
     } else if (time > oldgatetime[ch] + gatetime[ch] && !invert) {
         
         oldgatetime[ch] = time;
-        gLEDS[ch] = gGATES[ch] = 1;
         
-        return ch + 1;
+        if (!gatesoff) 
+        {
+            gGATES[ch] = true;
+            
+        } else if (ch == SUBGATE) {
+            
+            gSUBGATE = true;
+        }
+        
+        return 1;
     
     } else if (time > oldgatetime[ch] + gatetime[ch] && invert) {
         
         oldgatetime[ch] = time;
-        gLEDS[ch] = gGATES[ch] = 0;
+        
+        if (!gatesoff) 
+        {
+            gGATES[ch] = false;
+            
+        } else if (ch == SUBGATE) {
+            
+            gSUBGATE = false;
+        }
         
         return 0;
         
     } else if (time > oldgatetime[ch] + (gatetime[ch] - gatetime[ch] / length) && !invert) {
         
-        gLEDS[ch] = gGATES[ch] = 0;
+        if (!gatesoff) 
+        {
+            gGATES[ch] = false;
+            
+        } else if (ch == SUBGATE) {
+            
+            gSUBGATE = false;
+        }
         
         return 0;
         
     } else if (time > oldgatetime[ch] + (gatetime[ch] - gatetime[ch] / length) && invert) {
         
-        gLEDS[ch] = gGATES[ch] = 1;
+        if (!gatesoff) 
+        {
+            gGATES[ch] = true;
+            
+        } else if (ch == SUBGATE) {
+            
+            gSUBGATE = true;
+        }
         
-        return ch + 1;
+        return 1;
         
     } else {
         
@@ -1031,93 +1598,264 @@
     }
 }
 
+
 //-------------------------------------------------------------
-// SyncOut Sequence  beat(Note values) invert(invert Gate)
-
-inline void UpdateSync(int bpm, int beat, bool invert)
-{
-    static int bar, synctime, oldsynctime;
+// Check BPM
+
+inline int CheckBPM()
+{   
+    static int _bpm = -1;
+    int bpm;
     
-    int time = gTimer.read_us();
-    
-    bar = (60.0f / bpm) * 4000000;
-
-    synctime = bar / beat;
-    
-    if(beat == NRESET) 
+    if (gCtrlSW[0]) 
     {
-        bar = synctime = oldsynctime = gCLOCKOUT = 0;
+        bpm = 0;
+
+        return bpm;
     }
     
-    if((time > oldsynctime + synctime) && !invert)
+    if (!gCtrl[0]) 
     {
-        oldsynctime = time;
-        gCLOCKOUT = 1;
-        
-    } else if ((time > synctime - (synctime / 2)) && !invert) {
+        bpm = gArdCtrl[0] * 0.25f + 5;
+
+        if (abs(bpm - _bpm) > 1)
+        {
+            _bpm = bpm;
+            
+            sendMes.setTopAddress("/bpm");
+            sendMes.setArgs("i", bpm);
+            osc.sendOsc(&sendMes);
+        }
     
-        gCLOCKOUT = 0;
+    } else if (gCtrl[0]) {
+
+        bpm = (gCtrl[0] * 240 + 5);
+
+        if (abs(bpm - _bpm) > 1)
+        {
+            _bpm = bpm;
+            
+            sendMes.setTopAddress("/bpm");
+            sendMes.setArgs("i", bpm);
+            osc.sendOsc(&sendMes);
+        }
+    }
+                        
+    return bpm;
+}
+
+//-------------------------------------------------------------
+// Check Mode SW
+
+inline void CheckModeSW()
+{   
+    if (gMode < MODE_TOTAL - 1) 
+    {   
+        ++gMode;
+            
+    } else {
+                
+        gMode = 0;
+    }
+    
+    gCLOCKOUT = gGATES[0] = gGATES[1] = gGATES[2] = gGATES[3] = false;
+    
+    if (gMode == MODE_SEQ || gMode == MODE_185 || gMode == MODE_EUC)
+    {
+        gTimer.start();     // Sequencer Timer Start
+        midi.begin(1);
         
-    } else if((time > oldsynctime + synctime) && invert) {
-        
-        oldsynctime = time;
-        gCLOCKOUT = 0;
-        
-    } else if ((time > synctime - (synctime / 2)) && invert) {
-    
-        gCLOCKOUT = 1;
+    } else {
+            
+        gTimer.stop();      // Sequencer Timer Stop
     }
     
 }
 
 //-------------------------------------------------------------
-// CV meter
-
-inline void CVMeter(int ch, const unsigned int *level)
-{       
-    gLCD.locate ( ch, 0 );
-    gLCD.putc(*level * 0.000205729);     // put custom char
+// Print LCD Mode Status
+
+inline void LCD()
+{
+    static int _mode = -1;
+    static int _qmode = -1;
+    static int qmode;
+    
+    if (_mode != gMode)
+    {
+        sendMes.setTopAddress("/mode");
+        
+        switch (gMode) 
+            {
+                case MODE_Calb: 
+                    gLCD.locate( 9, 0 );
+                    gLCD.printf("CLB|880");
+                    
+                    sendMes.setArgs("s", "Calibration");
+                    osc.sendOsc(&sendMes);
+                    
+                    sendMes.setTopAddress("/scale");
+                    sendMes.setArgs("s", "880Hz");
+                    
+                    _qmode = -1;
+                    
+                    break;
+                
+                case MODE_OSC:
+                    gLCD.locate( 9, 0 );
+                    gLCD.printf("OSC|");
+                    
+                    sendMes.setArgs("s", "OSCtoCV");
+                    
+                    break;
+
+                case MODE_SEQ:  
+                    gLCD.locate( 9, 0 );
+                    gLCD.printf("ASR|");
+                    
+                    sendMes.setArgs("s", "ASR SEQ");
+                    
+                    break;
+                    
+                case MODE_185:  
+                    gLCD.locate( 9, 0 );
+                    gLCD.printf("185|");
+            
+                    sendMes.setArgs("s", "M185 SEQ");
+            
+                    break;
+                        
+                case MODE_EUC:  
+                    gLCD.locate( 9, 0 );
+                    gLCD.printf("EUC|");
+                    
+                    sendMes.setArgs("s", "Euclidean SEQ");
+                    
+                    break;
+                    
+                default:
+                    break;
+            }
+            
+            osc.sendOsc(&sendMes);
+            _mode = gMode;
+    }
+    
+    qmode = (gCtrl[1] * (SCALE_NUM - 1));
+    
+    if ((_qmode != qmode) && gMode)
+    {
+        sendMes.setTopAddress("/scale");
+        
+        switch (qmode) 
+            {
+                case Lin:
+                    gLCD.locate( 13, 0 );
+                    gLCD.printf("lin");
+
+                    sendMes.setArgs("s", "Linear");
+
+                    break;
+                    
+                case Chr:
+                    gLCD.locate( 13, 0 );
+                    gLCD.printf("chr");
+
+                    sendMes.setArgs("s", "Chromatic");
+
+                    break;
+                
+                case Maj:
+                    gLCD.locate( 13, 0 );
+                    gLCD.printf("maj");
+                    
+                    sendMes.setArgs("s", "Major");
+
+                    break;
+            
+                case M7:
+                    gLCD.locate( 13, 0 );
+                    gLCD.printf("ma7");
+                    
+                    sendMes.setArgs("s", "Major7");
+
+                    break;
+                
+                case Min7:
+                    gLCD.locate( 13, 0 );
+                    gLCD.printf("mi7");
+                    
+                    sendMes.setArgs("s", "Minor7");
+
+                    break;
+                    
+                case Dor:
+                    gLCD.locate( 13, 0 );
+                    gLCD.printf("dor");
+                    
+                    sendMes.setArgs("s", "Dorian");
+
+                    break;
+        
+                case Min:
+                    gLCD.locate( 13, 0 );
+                    gLCD.printf("min");
+                    
+                    sendMes.setTopAddress("/scale");
+                    sendMes.setArgs("s", "Minor");
+
+                    break;
+                
+                case S5th:
+                    gLCD.locate( 13, 0 );
+                    gLCD.printf("5th");
+                    
+                    sendMes.setArgs("s", "5th");
+
+                    break;
+                
+                case Wht:
+                    gLCD.locate( 13, 0 );
+                    gLCD.printf("wht");
+                    
+                    sendMes.setArgs("s", "Whole Tone");
+                    break;
+                    
+                default:
+                    break;
+            }
+            
+            osc.sendOsc(&sendMes);
+            _qmode = qmode;
+    }
+
 }
 
 //-------------------------------------------------------------
-// Print LCD Mode Status
-
-void LCD()
-{
-    switch(gMode) 
-        {
-            case MODE_Calb: 
-                gLCD.locate( 9, 0 );
-                gLCD.printf("Calibr "); 
-                break;
-                
-            case MODE_LIN:
-                gLCD.locate( 9, 0 );
-                gLCD.printf("OSC-CV ");
-                break;
-
-            case MODE_SEQ:  
-                gLCD.locate( 9, 0 );
-                gLCD.printf("SHIFTCV");
-                break;
-        }
+// CV Meter
+
+inline void UpdateCVMeter(int ch, const unsigned int *level)
+{       
+    gLCD.locate ( ch, 0 );
+    gLCD.putc(*level * 0.0002192f);     // put custom char
 }
 
+
 //-------------------------------------------------------------
-// Write command Custom Char LCD CGRAM(CV Meter) 
+// Write command Custom Char LCD CGRAM for CV Meter)
 
 void WriteCustomChar(unsigned char addr, unsigned char *c)
 {   
     char cnt = 0;
     addr = ((addr << 3) | 0x40);
     
-    while(cnt < 0x08)
+    while (cnt < 0x08)
     {
         gLCD.writeCommand(addr | cnt);
         gLCD.writeData(*c);
         
-        cnt++;
-        c++;
+        ++cnt;
+        ++c;
     }
 }
 
@@ -1131,7 +1869,7 @@
 //  printf("Setting up...\r\n");
     EthernetErr ethErr = gEth.setup();
     
-    if(ethErr)
+    if (ethErr)
     {
         gLCD.locate( 0, 1 );
         gLCD.printf("Error in setup.");
@@ -1147,6 +1885,7 @@
     
     gLCD.locate( 0, 1 );
     gLCD.printf("%03d.%03d.%03d.%03d", gEth.getIp()[0], gEth.getIp()[1], gEth.getIp()[2], gEth.getIp()[3]);
+    
     wait(1.0);
     
     return 0;
@@ -1159,40 +1898,40 @@
 {
     size_t len = 0;
     
-    for(;;) 
+    for (;;) 
     {
         unsigned x = *(unsigned*)s;
-        if((x & 0xFF) == 0) return len;
-        if((x & 0xFF00) == 0) return len + 1;
-        if((x & 0xFF0000) == 0) return len + 2;
-        if((x & 0xFF000000) == 0) return len + 3;
+        if ((x & 0xFF) == 0) return len;
+        if ((x & 0xFF00) == 0) return len + 1;
+        if ((x & 0xFF0000) == 0) return len + 2;
+        if ((x & 0xFF000000) == 0) return len + 3;
         s += 4, len += 4;
     }
 }
 
 //-------------------------------------------------------------
-// Handller receive UDP Packet
+// Handller receive OSC UDP Packet
 
 inline void onUDPSocketEvent(UDPSocketEvent e)
 {
-    union OSCarg msg[10];
-    char buf[768] = {0};
-    int num, len;
-    int recvlen;
+    static union OSCarg msg[10];
+    static char buf[896] = {0};
+    static int recvlen;
+    static int num, len, offset;
     int messagepos = 0;
     bool bundleflag = false;
     
     Host host;
     
-    recvlen = gUdp.recvfrom(buf, 768, &host);  // packet length
-            
-    switch(e)
+    switch (e)
     {
         case UDPSOCKET_READABLE: // The only event for now
-            
-        if(recvlen <= 0)  break;
+        
+        recvlen = gUdp.recvfrom(buf, 896, &host);  // packet length    
         
-        if(buf[0] == '#') // #bundle
+        if (recvlen <= 0)  break;
+        
+        if (!bundleflag && buf[0] == '#') // #bundle
         {
             messagepos += 16;     // skip #bundle & timetag
             recvlen -= 16;
@@ -1201,117 +1940,960 @@
         }
         
         do {
-                if(bundleflag)
+                if (bundleflag)
                 {
                     messagepos += 4;
                     recvlen -= 4;
-                
-                    if(recvlen <= 0)
+                    
+                    if (recvlen <= 8)
                     {
                         bundleflag = false;
                         break;
                     }
                 }
                 
-                if(getOSCmsg(buf + messagepos, msg) == -1)  continue;
+                if (getOSCmsg(buf + messagepos, msg) == -1)  continue;
             
-                len = strlen(msg[0].address);
+                len = strlength(msg[0].address);
         
-                if(isdigit(msg[0].address[len-1])) 
+                if (isdigit(msg[0].address[len-1])) 
                 {       
                     num = msg[0].address[len-1] - '0' - 1;
-            
+                    
+                    offset = 1;
+                    
+                    if (isdigit(msg[0].address[len-2])) 
+                    {
+                        offset = 2;
+                        num += 10;
+                    }
+                        
                 } else {
             
                     num = -1;
                 }
         
             // address pattern SYNC & GATE (Type Tag int, float)
-                if(!strncmp(msg[0].address+(len-1)-4, "sync", 4)) 
+                if (!strncmp(msg[0].address+(len-offset)-4, "sync", 4)) 
                 { 
-                    if(msg[2].i != 0) gCLOCKOUT = 1;
-                    else              gCLOCKOUT = 0;
+                    if (msg[2].i != 0) gCLOCKOUT = true;
+                    else              gCLOCKOUT = false;
                     continue;
 
-                } else if (!strncmp(msg[0].address+(len-1)-4, "gate", 4) && (num != -1)) {
-                    if(num > 3) continue;
-                    if(msg[2].i != 0) gLEDS[num] = gGATES[num] = 1;
-                    else              gLEDS[num] = gGATES[num] = 0;
+                } else if (!strncmp(msg[0].address+(len-offset)-4, "gate", 4) && (num != -1)) {
+                    if (num > 3) continue;
+                    if (msg[2].i != 0) gGATES[num] = true;
+                    else              gGATES[num] = false;
                     continue;
             // (touchOSC Control push, toggle)
-                } else if (!strncmp(msg[0].address+(len-1)-4, "push", 4) && (num != -1)) {     
-                    if(num > 4) continue;
-                    if(msg[2].i != 0) gLEDS[num] = gGATES[num] = 1;
-                    else              gLEDS[num] = gGATES[num] = 0;
-                    continue;
-                
-                } else if (!strncmp(msg[0].address+(len-1)-6, "toggle", 6) && (num != -1)) {
-                    if(num > 4) continue;
-                    if(msg[2].i != 0) gLEDS[num] = gGATES[num] = 1;
-                    else              gLEDS[num] = gGATES[num] = 0;
-                    continue;
-                        
-                } else if (!strncmp(msg[0].address,"/1/multipush",12) && (num != -1)) {
-                    if(num > 4) continue;
-                    if(msg[2].i != 0) gLEDS[num] = gGATES[num] = 1;
-                    else              gLEDS[num] = gGATES[num] = 0;
-                    continue;
-            // address pattern CV (Type Tag float)  
-                } else if(!strncmp(msg[0].address+(len-1)-2, "cv", 2) && (num != -1)) {
-                    if(num > 7) continue;
-                    if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N);
+                } else if (!strncmp(msg[0].address+(len-offset)-5, "fader", 5) && (num != -1)) {
+                    if (num > 7) continue;                                              
+                    gOSC_cv[num] = msg[2].f * (SCALING_N);
                     continue;
-            // (touchOSC Control fader, rotary, xy, multixy, multifader)        
-                } else if (!strncmp(msg[0].address+(len-1)-5, "fader", 5) && (num != -1)) {
-                    if(num > 7) continue;                                              
-                    if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N);
-                    continue;
-
-                } else if (!strncmp(msg[0].address+(len-1)-6, "rotary", 6) && (num != -1)) { 
-                    if(num > 7) continue;
-                    if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N);
-                    continue;
-                
-                } else if (!strncmp(msg[0].address+(len-1)-2, "xy", 2) && (num != -1)) {
-                    if(num > 7) continue;
-                    if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N);
-                    if(msg[1].typeTag[1] == 'f') gOSC_cv[++num] = msg[3].f * (SCALING_N);
-                    continue;
-                        
-                } else if (!strncmp(msg[0].address+(len-1)-9, "multixy1/", 9) && (num != -1)) {
-                    if(num > 7) continue;
-                    if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N);
-                    if(msg[1].typeTag[1] == 'f') gOSC_cv[++num] = msg[3].f * (SCALING_N);
+
+                } else if (!strncmp(msg[0].address+(len-offset)-9, "multixy1/", 9) && (num != -1)) {
+                    if (num > 7) continue;
+                    if (msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N);
+                    if (msg[1].typeTag[1] == 'f') gOSC_cv[++num] = msg[3].f * (SCALING_N);
                     continue;
     
-                } else if (!strncmp(msg[0].address+(len-1)-12, "multifader1/", 12) && (num != -1)) {
-                    if(num > 7) continue;
-                    if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N);
+                } else if (!strncmp(msg[0].address+(len-offset)-12, "multifader1/", 12) && (num != -1)) {
+                    if (num > 7) continue;
+                    if (msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N);
                     continue;
-            // (touchOSC multifader for Sequencer Mode)
-                } else if (!strncmp(msg[0].address+(len-1)-11, "sequencer1/", 11) && (num != -1)) {
-                    if(num > 7) continue;
-                    if(msg[1].typeTag[1] == 'f') gSeq_cv1[num] = msg[2].f * (SCALING_N);
+                    
+                } else if (!strncmp(msg[0].address+(len-offset)-10, "sequencer/", 10) && (num != -1)) {
+                    
+                    if (num > 15) continue;
+                    gSeq_cv[num] = msg[2].f * (SCALING_N);
                     continue;
                             
-                } else if (!strncmp(msg[0].address+(len-1)-11, "sequencer2/", 11) && (num != -1)) {
-                    if(num > 7) continue;
-                    if(msg[1].typeTag[1] == 'f') gSeq_cv2[num] = msg[2].f * (SCALING_N);
-                    continue;
-            // address pattern for control
-                } else if (!strncmp(msg[0].address+(len-1)-6, "ctrlsw", 6) && (num != -1)) {
-                    if(num > 5) continue;
-                    if(msg[2].i != 0) gCtrlSW[num] = true;
+                } else if (!strncmp(msg[0].address+(len-offset)-6, "ctrlsw", 6) && (num != -1)) {
+                    if (num > 7) continue;
+                    if (msg[2].i != 0) gCtrlSW[num] = true;
                     else              gCtrlSW[num] = false;
                     continue;
                                                 
-                } else if (!strncmp(msg[0].address+(len-1)-4, "ctrl", 4) && (num != -1)) {
-                    if(num > 5) continue;                                             
-                    if(msg[1].typeTag[1] == 'f') gCtrl[num] = msg[2].f;
+                } else if (!strncmp(msg[0].address+(len-offset)-4, "ctrl", 4) && (num != -1)) {
+                    if (num > 7) continue;                                             
+                    gCtrl[num] = msg[2].f;
+                    continue;
+                    
+                } else if (!strncmp(msg[0].address+(len-offset)-9, "pulsecnt/", 9) && (num != -1)) {
+                    if (num > 7) continue;
+                    gPulseCount[num] = msg[2].f;
+                    continue;
+                    
+                } else if (!strncmp(msg[0].address+(len-offset)-9, "gatemode/", 9) && (num != -1)) {
+                    if (num > 15) continue;
+                    gGateMode[num] = msg[2].f;
+                    continue;
+                    
+                } else if (!strncmp(msg[0].address+(len-offset)-6, "slide/", 6) && (num != -1)) {
+                    if (num > 15) continue;
+                    gSlide[num] = msg[2].f;
+                    continue;
+                    
+                } else if (!strncmp(msg[0].address+(len-offset)-4, "euca", 4) && (num != -1)) {
+                    if (num > 5) continue;                                             
+                    gEucA[num] = msg[2].f;
+                    continue;
+                    
+                } else if (!strncmp(msg[0].address+(len-offset)-4, "eucb", 4) && (num != -1)) {
+                    if (num > 5) continue;                                             
+                    gEucB[num] = msg[2].f;
+                    continue;
+                    
+                } else {
                     continue;
                 }
                 
-            } while(bundleflag);
+            } while (bundleflag);                   
+    }
+}
+
+//-------------------------------------------------------------
+// Euclidean Sequencer
+
+void EuclideanSeq(int trigger, bool reset, bool gatesoff) {
+    /*
+       What's in the loop: 
+       Update euc_time variable 
+       Check to see if it is euc_time go go to sleep 
+       Changes routine - update beat_holder when channelbeats changes - triggered by changes == true
+       Trigger routines - on trigget update displays and pulse
+       Read encoders 
+       Read switches
+     */
+
+    static uint8_t nn, kk, oo;
+    static uint8_t changes[MAXCHANNELS] = {0};
+    static int nknob, kknob, oknob;
+    static int _nknob, _kknob, _oknob;
+    static bool triggerState = false;
+    
+    uint8_t i, ch;
+    uint8_t maxn = MAXSTEPS; // maximums and minimums for n and k
+    uint8_t minn = 1;
+    uint8_t mink = 1; 
+    uint8_t mino = 0; 
+    
+    static uint8_t active_channel;  
+    
+    euc_time = gTimer.read_ms();
+
+    nn = channelbeats[active_channel][0];  
+    kk = channelbeats[active_channel][1]; 
+    oo = channelbeats[active_channel][3];
+    
+    // UPDATE BEAT HOLDER WHEN KNOBS ARE MOVED
+    if (changes[active_channel]) {
+        
+        beat_holder[active_channel] = Euclid(nn, kk, oo);
+        
+        switch (changes[active_channel]) 
+        {
+            case 1:
+            case 3:
+                for (int i = 0; i < MAXSTEPS; ++i) {
+                
+                    if (BitRead(beat_holder[active_channel], nn - 1 - i) && (i < nn)) {
+                        sendMes.setTopAddress(SetMatrixAddress(active_channel * 2, i, true));
+                        sendMes.setArgs("i", 1);
+                        osc.sendOsc(&sendMes);          
+                    
+                    } else {
+                        
+                        sendMes.setTopAddress(SetMatrixAddress(active_channel * 2, i, true));
+                        sendMes.setArgs("i", 0);
+                        osc.sendOsc(&sendMes);      
+                    }
+                }
+            
+                break;
+            
+            case 2:
+                for (int i = 0; i < MAXSTEPS; ++i) {
+            
+                    if (i < nn) {
+                        sendMes.setTopAddress(SetMatrixAddress(active_channel * 2, i, true));
+                        sendMes.setArgs("i", 1);
+                        osc.sendOsc(&sendMes);          
                     
+                    } else {
+                        
+                        sendMes.setTopAddress(SetMatrixAddress(active_channel * 2, i, true));
+                        sendMes.setArgs("i", 0);
+                        osc.sendOsc(&sendMes);          
+                    }
+                }
+        
+                break;
+            
+            default: 
+                break;
+        }
+        
+        changes[active_channel] = 0;
+        last_changed[active_channel] = gTimer.read_ms();
+    }
+    
+    // ANALOG PULSE TRIGGER
+    if (trigger && !triggerState) {
+        
+        Sync(active_channel, gatesoff);
+        triggerState = true;
+    
+    } else if (!trigger) {
+        
+        triggerState = false;
+    }
+
+    // READ K KNOB 
+    kknob = EncodeReadK(active_channel);
+    
+    if (_kknob != kknob) {
+        
+        _kknob = kknob;
+        
+        if (kknob != 0 && (euc_time - last_read[active_channel] > READ_DELAY)) {
+        
+            if ((kk + kknob) > nn) {          
+            
+                kknob = 0;
+                kk = nn;
+            
+            } else if ((kk + kknob) < mink) {
+            
+                kknob = 0;
+                kk = mink;
+            };
+
+            kk = channelbeats[active_channel][1] = (kk + kknob); // update with encoder reading
+
+            last_read[active_channel] = gTimer.read_ms();
+            changes[active_channel] = 1; // k change = 1
+        }
+    }
+    
+    // READ N KNOB 
+    nknob = EncodeReadN(active_channel);
+    
+    if (_nknob != nknob) {
+        
+        _nknob = nknob;
+        
+        if (nknob != 0 && (euc_time - last_read[active_channel] > READ_DELAY)) { 
+
+            if ((nn + nknob) > maxn) {
+            
+                nknob = 0;
+                nn = maxn;
+            
+            } else if ((nn + nknob) < minn) {
+            
+                nknob = 0;
+                nn = minn;
+            };
+
+            if (kk > (nn + nknob)) {// check if new n is lower than k + reduce K if it is 
+                channelbeats[active_channel][1] = (nn + nknob);
+            }; 
+
+            if (oo > (nn + nknob - 1)) {// check if new n is lower than o + reduce o if it is 
+                channelbeats[active_channel][3] = (nn + nknob - 1);
+            }; 
+
+            nn = channelbeats[active_channel][0] = (nn + nknob); // update with encoder reading
+            oo = channelbeats[active_channel][3];
+
+            last_read[active_channel] = gTimer.read_ms();
+            changes[active_channel] = 2; // n change = 2 
+        }
+        
+    }
+    
+    // READ O KNOB 
+    oknob = EncodeReadO(active_channel);
+    
+    if (_oknob != oknob) {
+        
+        _oknob = oknob;
+            
+        if (oknob != 0 && (euc_time - last_read[active_channel] > READ_DELAY)) { 
+            // Sense check o encoder reading to prevent crashes 
+
+            if ((oo + oknob) > (nn - 1)) {
+            
+                oknob = 0;
+                oo = (nn - 1);
+        
+            } else if ((oo + oknob) < mino) {
+            
+                oknob = 0;
+                oo = mino;
+            }
+
+            channelbeats[active_channel][3] = (oo + oknob);
+        
+            last_read[active_channel] = gTimer.read_ms();
+            changes[active_channel] = 3; // o change = 3
+        }
+        
+    }
+    
+    // ENABLE RESET BUTTON ** ADD FLASH RESET HERE ***
+    if (gCtrlSW[1] && channelbeats[active_channel][2]) {
+        
+        for (ch = 0; ch < channels; ++ch) {
+            channelbeats[ch][2] = 0; 
+        }
+    }
+    
+    // Stop & Reset (gCtrlSW[0])
+    if (reset) {
+        
+        for (ch = 0; ch < channels; ++ch) {
+            
+            channelbeats[ch][2] = 0;
+            
+            for (i = 0; i < MAXSTEPS; ++i) {
+            
+                sendMes.setTopAddress(SetMatrixAddress(ch * 2 + 1, i, true));
+                sendMes.setArgs("i", 0);
+                osc.sendOsc(&sendMes);
+            }
+            
+        }
+        
+    }
+    
+    // TURN OFF ANY LIGHTS THAT ARE ON 
+    if ((euc_time - last_sync) > pulse_length && lights_active) {
+        
+        for (ch = 0; ch < channels; ++ch) {
+            sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 3 - ch, true));
+            sendMes.setArgs("i", 0);
+            osc.sendOsc(&sendMes);
+            
+            sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 5, true));
+            sendMes.setArgs("i", 0);
+            osc.sendOsc(&sendMes);
+            
+      }
+      
+      lights_active = false; 
+    }
+    
+    // FINISH ANY PULSES THAT ARE ACTIVE - PULSES LAST 1/4 AS LONG AS LIGHTS 
+    if (euc_time - last_sync > (pulse_length / 4) && pulses_active) {
+        
+        for (ch = 0; ch < channels; ++ch) {
+            
+            if (!gatesoff)
+            {
+                gGATES[ch] = false;
+                gCLOCKOUT = false;
+                //digitalWrite(sparepin, LOW);
+            }
+        }
+        
+        pulses_active = false; 
+    }
+    
+    ++active_channel;
+    active_channel &= (channels - 1);
+}
+
+//-------------------------------------------------------------
+// Euclid calculation function
+
+unsigned int Euclid(int n, int k, int o) { // inputs: n=total, k=beats, o = offset
+    int pauses = (n - k);
+    int pulses = k;
+    int offset = o;
+    int steps = n;
+    int per_pulse = (pauses / k);
+    int remainder = (pauses % pulses);  
+    unsigned int workbeat[n];
+    unsigned int outbeat;
+    uint16_t outbeat2;
+    int workbeat_count = n;
+    int a_remainder, b_remainder;
+    int groupa, groupb;
+    int i, j; 
+    int trim_count;
+
+    for (i = 0; i < n; ++i) { // Populate workbeat with unsorted pulses and pauses 
+
+        if (i < pulses) {
+
+            workbeat[i] = 1;
+
+        } else {
+
+            workbeat[i] = 0;
+        }
+    }
+
+    if (per_pulse > 0 && remainder < 2) { // Handle easy cases where there is no or only one remainer
+
+        for (i = 0; i < pulses; ++i) {
+
+            for (j = (workbeat_count - 1); j > (workbeat_count - per_pulse - 1); --j) {
+                workbeat[i]  = ConcatBin(workbeat[i], workbeat[j]);
+            }
+
+            workbeat_count = (workbeat_count - per_pulse);
+            
+        }
+
+        outbeat = 0; // Concatenate workbeat into outbeat - according to workbeat_count
+
+        for (i = 0; i < workbeat_count; ++i) {
+            outbeat = ConcatBin(outbeat, workbeat[i]);
+        }
+
+
+        if (offset != 0) {
+            
+            outbeat2 = BitReadOffset(offset, outbeat, steps); // Add offset to the step pattern
+
+        } else {
+            
+            outbeat2 = outbeat;
+        }
+
+        return outbeat2;
+
+    } else { 
+
+        groupa = pulses;
+        groupb = pauses; 
+
+        while (groupb > 1) { //main recursive loop
+
+            if (groupa > groupb) { // more Group A than Group B
+                
+                a_remainder = (groupa - groupb); // what will be left of groupa once groupB is interleaved 
+                trim_count = 0;
+
+                for (i = 0; i < (groupa - a_remainder); ++i) { //count through the matching sets of A, ignoring remaindered
+                    workbeat[i]  = ConcatBin(workbeat[i], workbeat[workbeat_count - 1 - i]);
+                    ++trim_count;
+                }
+                
+                workbeat_count = (workbeat_count - trim_count);
+
+                groupa = groupb;
+                groupb = a_remainder;
+
+            } else if (groupb > groupa) { // More Group B than Group A
+                
+                b_remainder = (groupb - groupa); // what will be left of group once group A is interleaved 
+                trim_count = 0;
+
+                for (i = workbeat_count-1; i >= (groupa + b_remainder); --i) { //count from right back through the Bs
+                    workbeat[workbeat_count - i - 1] = ConcatBin(workbeat[workbeat_count - 1 - i], workbeat[i]);
+
+                    ++trim_count;
+                }
+
+                workbeat_count = (workbeat_count - trim_count);
+                groupb = b_remainder;
+
+            } else if (groupa == groupb) { // groupa = groupb 
+                
+                trim_count = 0;
+
+                for (i = 0; i < groupa; ++i) {
+                    workbeat[i] = ConcatBin(workbeat[i], workbeat[workbeat_count - 1 - i]);
+                    ++trim_count;
+                }
+
+                workbeat_count = (workbeat_count - trim_count);
+                groupb = 0;
+
+            }
+        }
+
+        outbeat = 0; // Concatenate workbeat into outbeat - according to workbeat_count
+
+        for (i = 0; i < workbeat_count; ++i) {
+            
+            outbeat = ConcatBin(outbeat, workbeat[i]);
+        }
+
+        if (offset != 0) {
+            
+            outbeat2 = BitReadOffset(offset, outbeat, steps); // Add offset to the step pattern
+
+        } else {
+
+            outbeat2 = outbeat;
+        }
+
+        return outbeat2;
     }
 }
+
+//-------------------------------------------------------------
+// Reads a bit of a number
+
+inline int BitRead(uint16_t b, int bitPos) {
+    int x;
+        
+    x = b & (1 << bitPos);
+    
+    return x == 0 ? 0 : 1;
+}
+
+//-------------------------------------------------------------
+// Function to right rotate n by d bits
+
+uint16_t BitReadOffset(int shift, uint16_t value, uint16_t pattern_length) {
+    uint16_t mask = ((1 << pattern_length) - 1);
+    value &= mask;
+
+    return ((value >> shift) | (value << (pattern_length - shift))) & mask;
+}
+
+//-------------------------------------------------------------
+// Function to find the binary length of a number by counting bitwise
+
+int findlength(unsigned int bnry) {
+    bool lengthfound = false;
+    int i;
+    int length = 1; // no number can have a length of zero - single 0 has a length of one, but no 1s for the sytem to count
+
+    for (i = 32; i >= 0; i--) {
+
+        if ((BitRead(bnry, i)) && !lengthfound) {
+            length = (i + 1);
+            lengthfound = true;
+        }
+        
+    }
+
+    return length;
+}
+
+//-------------------------------------------------------------
+// Function to concatenate two binary numbers bitwise
+
+unsigned int ConcatBin(unsigned int bina, unsigned int binb) {
+    int binb_len = findlength(binb);
+    unsigned int sum = (bina << binb_len);
+
+    sum = sum | binb;
+
+    return sum;
+}
+
+//-------------------------------------------------------------
+// routine triggered by each beat
+
+void Sync(int active_channel, bool gatesoff) {
+    int read_head, erase;
+    int rand_vel, rand_len;
+    int ch, i;
+    static int masterclock;
+    
+    if (masterclock % 2 == 0) {
+        sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 7, true));
+        sendMes.setArgs("i", 1);
+        osc.sendOsc(&sendMes);
+    
+    } else {
+        
+        sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 7, true));
+        sendMes.setArgs("i", 0);
+        osc.sendOsc(&sendMes);
+    }
+
+    // Cycle through channels 
+    for (ch = 0; ch < channels; ++ch) {
+        
+        read_head = (channelbeats[ch][0] - channelbeats[ch][2] - 1);  
+
+        if (ch != active_channel || (euc_time - last_changed[active_channel]) > DISPLAY_UPDATE) {
+            
+            if (channelbeats[ch][2] < MAXSTEPS) {
+                
+                for (i = 0; i < MAXSTEPS; ++i) {
+                    
+                    if (BitRead(beat_holder[ch],channelbeats[ch][0] - 1 - i) && i < channelbeats[ch][0]) {
+                        
+                        sendMes.setTopAddress(SetMatrixAddress(ch * 2, i, true));
+                        sendMes.setArgs("i", 1);
+                        osc.sendOsc(&sendMes);
+                    
+                    } else {
+                        
+                        sendMes.setTopAddress(SetMatrixAddress(ch * 2, i, true));
+                        sendMes.setArgs("i", 0);
+                        osc.sendOsc(&sendMes);
+                    }
+                    
+                }
+            }
+        }
+        
+        if (channelbeats[ch][2]) {
+            
+            if (!masterclock) {
+                
+                erase = MAXSTEPS - 1;
+                
+            } else {
+                
+                erase = masterclock - 1;
+            }
+            
+            sendMes.setTopAddress(SetMatrixAddress((ch * 2) + 1, erase, true));
+            sendMes.setArgs("i", 0);
+            osc.sendOsc(&sendMes);
+
+            sendMes.setTopAddress(SetMatrixAddress((ch * 2) + 1, masterclock, true));
+            sendMes.setArgs("i", 1);
+            osc.sendOsc(&sendMes);
+            
+            }
+            
+        // turn on pulses on channels where a beat is present  
+        if (BitRead(beat_holder[ch], read_head)) {
+            
+            if (!gatesoff)
+            {
+                gGATES[ch] = true; // pulse out
+            }
+            
+            sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 3 - ch, true));
+            sendMes.setArgs("i", 1);
+            osc.sendOsc(&sendMes);
+            
+            lights_active = pulses_active = true;
+            
+            if (!ch || (ch == 2)) { 
+                
+                rand_vel = 127 - (rand() / (RAND_MAX / 40)); // random velocity ch1, ch3
+                
+            } else {
+                
+                rand_vel = 95 - (rand() / (RAND_MAX / 70));  // random velocity ch2, ch4
+            }
+            
+            rand_len = 127 - (rand() / (RAND_MAX / 110));    // random Amp EG Decay
+            
+            midi.sendControlChange(0x07, rand_vel, (ch + 1)); // volca sample Vol
+            midi.sendControlChange(0x30, rand_len, (ch + 1)); // volca sample Amp EG Decay
+            midi.sendNoteOn(0, 127, (ch + 1)); // volca sample trriger on
+        }
+
+        // send off pulses to spare output for the first channel 
+        if (!(BitRead(beat_holder[ch], read_head)) && !ch) { // only relates to first channel
+            
+            if (!gatesoff)
+            {
+                gCLOCKOUT = true;
+            }
+            
+            sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 5, true));
+            sendMes.setArgs("i", 1);
+            osc.sendOsc(&sendMes);
+            
+            lights_active = pulses_active = true;
+        }
+
+        // move counter to next position, ready for next pulse  
+        ++channelbeats[ch][2];
+
+        if ((channelbeats[ch][2]) >= (channelbeats[ch][0])) {
+            channelbeats[ch][2] = 0; 
+        }
+    }
+    
+    ++masterclock;
+    masterclock &= (MAXSTEPS - 1);
+
+    pulse_length = ((euc_time - last_sync) / 5);
+    last_sync = euc_time;
+}
+
+/* 3 functions to read each encoder   
+   returns +1, 0 or -1 dependent on direction 
+   Contains no internal debounce, so calls should be delayed 
+ */
+
+//-------------------------------------------------------------
+// Check Euclidean Seq N(length) Value
+
+int EncodeReadN(int ch) {
+    static float _enc[4];
+    int result = 0;
+    
+    switch (ch)
+    {
+        case 0:
+        
+            if (gEucA[0] == 0) {
+                _enc[ch] = result = 0;
+        
+            } else if (gEucA[0] < _enc[ch]) {  
+                result = -1;
+                _enc[ch] = gEucA[0];
+    
+            } else if (gEucA[0] > _enc[ch]) { 
+                result = 1;
+                _enc[ch] = gEucA[0];
+            }
+            
+            break;
+        
+        case 1:
+        
+            if (gEucA[3] == 0) {
+                _enc[ch] = result = 0;
+    
+            } else if (gEucA[3] < _enc[ch]) {  
+                result = -1;
+                _enc[ch] = gEucA[3];
+
+            } else if (gEucA[3] > _enc[ch]) { 
+                result = 1;
+                _enc[ch] = gEucA[3];
+            }
+        
+            break;
+        
+        case 2:
+        
+            if (gEucB[0] == 0) {
+                _enc[ch] = result = 0;
+    
+            } else if (gEucB[0] < _enc[ch]) {  
+                result = -1;
+                _enc[ch] = gEucB[0];
+
+            } else if (gEucB[0] > _enc[ch]) { 
+                result = 1;
+                _enc[ch] = gEucB[0];
+            }
+        
+            break;
+        
+        case 3:
+        
+            if (gEucB[3] == 0) {
+                _enc[ch] = result = 0;
+    
+            } else if (gEucB[3] < _enc[ch]) {  
+                result = -1;
+                _enc[ch] = gEucB[3];
+
+            } else if (gEucB[3] > _enc[ch]) { 
+                result = 1;
+                _enc[ch] = gEucB[3];
+            }
+        
+            break;
+        
+        default:
+            break;
+    }
+    
+    return result;
+}
+
+//-------------------------------------------------------------
+// Check Euclidean Seq K(Density) Value
+
+int EncodeReadK(int ch) { 
+    static float _enc[4];
+    int result = 0;
+    
+    switch (ch)
+    {
+        case 0:
+        
+            if (gEucA[1] == 0) {
+                _enc[ch] = result = 0;
+        
+            } else if (gEucA[1] < _enc[ch]) {  
+                result = -1;
+                _enc[ch] = gEucA[1];
+    
+            } else if (gEucA[1] > _enc[ch]) { 
+                result = 1;
+                _enc[ch] = gEucA[1];
+            }
+            
+            break;
+        
+        case 1:
+        
+            if (gEucA[4] == 0) {
+                _enc[ch] = result = 0;
+    
+            } else if (gEucA[4] < _enc[ch]) {  
+                result = -4;
+                _enc[ch] = gEucA[4];
+
+            } else if (gEucA[4] > _enc[ch]) { 
+                result = 4;
+                _enc[ch] = gEucA[4];
+            }
+        
+            break;
+        
+        case 2:
+        
+            if (gEucB[1] == 0) {
+                _enc[ch] = result = 0;
+    
+            } else if (gEucB[1] < _enc[ch]) {  
+                result = -1;
+                _enc[ch] = gEucB[1];
+
+            } else if (gEucB[1] > _enc[ch]) { 
+                result = 1;
+                _enc[ch] = gEucB[1];
+            }
+        
+            break;
+        
+        case 3:
+        
+            if (gEucB[4] == 0) {
+                _enc[ch] = result = 0;
+    
+            } else if (gEucB[4] < _enc[ch]) {  
+                result = -1;
+                _enc[ch] = gEucB[4];
+
+            } else if (gEucB[4] > _enc[ch]) { 
+                result = 1;
+                _enc[ch] = gEucB[4];
+            }
+        
+            break;
+        
+        default:
+            break;      
+    }
+    
+    return result;
+}
+
+//-------------------------------------------------------------
+// Check Euclidean Seq O(Offset) Value
+
+int EncodeReadO(int ch) { 
+    static float _enc[4];
+    int result = 0;
+    
+    switch (ch)
+    {
+        case 0:
+        
+            if (gEucA[2] == 0) {
+                _enc[ch] = result = 0;
+        
+            } else if (gEucA[2] < _enc[ch]) {  
+                result = -1;
+                _enc[ch] = gEucA[2];
+    
+            } else if (gEucA[2] > _enc[ch]) { 
+                result = 1;
+                _enc[ch] = gEucA[2];
+            }
+            
+            break;
+        
+        case 1:
+        
+            if (gEucA[5] == 0) {
+                _enc[ch] = result = 0;
+    
+            } else if (gEucA[5] < _enc[ch]) {  
+                result = -1;
+                _enc[ch] = gEucA[5];
+
+            } else if (gEucA[5] > _enc[ch]) { 
+                result = 1;
+                _enc[ch] = gEucA[5];
+            }
+        
+            break;
+        
+        case 2:
+        
+            if (gEucB[2] == 0) {
+                _enc[ch] = result = 0;
+    
+            } else if (gEucB[2] < _enc[ch]) {  
+                result = -1;
+                _enc[ch] = gEucB[2];
+
+            } else if (gEucB[2] > _enc[ch]) { 
+                result = 1;
+                _enc[ch] = gEucB[2];
+            }
+        
+            break;
+        
+        case 3:
+        
+            if (gEucB[5] == 0) {
+                _enc[ch] = result = 0;
+    
+            } else if (gEucB[5] < _enc[ch]) {  
+                result = -1;
+                _enc[ch] = gEucB[5];
+
+            } else if (gEucB[5] > _enc[ch]) { 
+                result = 1;
+                _enc[ch] = gEucB[5];
+            }
+        
+            break;
+        
+        default:
+            break;
+    }
+    
+    return result;
+}
+
+inline char * SetMatrixAddress(int row, int column, bool euclid) {
+    static char address[32];
+    char col[2];
+    char ch[2];
+    
+    if(euclid)
+    {
+        strcpy(address, MATRIX_ADDRESS);
+    
+    } else {
+        
+        strcpy(address, STEP_INDICATOR_ADDRESS);
+    }
+    
+    sprintf(col, "%d", column + 1);
+    strcat(address, col);
+    
+    if(euclid)
+    {
+        strcat(address, "/");
+        
+        sprintf(ch, "%d", row + 1);
+        strcat(address, ch);
+    
+    } else {
+        
+        strcat(address, "/1");
+    }
+    
+    return address;
+}
+