casiotone 401 / Mbed 2 deprecated OSCtoCVConverter

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

Revision:
12:33c8f06c2e03
Child:
13:3f42e451a8d3
diff -r ef7610cd7ebe -r 33c8f06c2e03 example.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/example.h	Sun Apr 14 00:54:10 2013 +0000
@@ -0,0 +1,1597 @@
+//-------------------------------------------------------------
+//                  TI DAC8568  OSC-CV Converter
+//
+//   DAC8568 16bit Octal DAC http://www.ti.com/product/dac8568
+//
+//   referred to
+//   xshige's OSCReceiver
+//   http://mbed.org/users/xshige/programs/OSCReceiver/
+//   radiojunkbox's OSC-CV_Example
+//   http://mbed.org/users/radiojunkbox/code/KAMUI_OSC-CV_Example/
+//   Robin Price's Homebrew midi-cv box
+//   http://crx091081gb.net/?p=69
+//   Masahiro Hattori's TextLCD Module Functions
+//   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
+//
+// Released under the MIT License: http://mbed.org/license/mit
+//-------------------------------------------------------------
+
+#pragma O3
+#pragma Otime
+
+#include "mbed.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 <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+
+//-------------------------------------------------------------
+// Define
+
+#define MODE_Calb           0        // Calibration (for VCO Tuning)
+#define MODE_LIN            1        // Linear LinearCV
+#define MODE_QChr           2        // Chromatic   Quantize Mode
+#define MODE_QMaj           3        // Major
+#define MODE_QDor           4        // Dorian
+#define MODE_Q5th           5        // 5th
+#define MODE_QWht           6        // Wholetone
+#define MODE_SEQ            7        // Sequencer & Shift Register
+#define MODE_SHIF           8        // Mode Shift
+
+#define MODE_NUM            9        // Modes
+
+#define Lin                 0        // Linear LinearCV
+#define Chr                 1        // Chromatic
+#define Maj                 2        // Major
+#define M7                  3        // Major7
+#define Min7                4        // Minor7
+#define Dor                 5        // Dorian
+#define Min                 6        // Minor
+#define S5th                7        // 5th
+#define Wht                 8        // Wholetone
+
+#define 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            48000000 // 40Mbps SPI Clock
+#define SCALING_N           38400.0
+#define INPUT_PORT          12345    // Input Port Number
+
+#define POLLING_INTERVAL    20       // Polling Interval (us)
+
+//-------------------------------------------------------------
+// DAC8568 Control Bits (See datasheet)
+
+#define WRITE               0x00
+#define UPDATE              0x01
+#define WRITE_UPDATE_ALL    0x02     // LDAC Write to Selected Update All
+#define WRITE_UPDATE_N      0x03     // LDAC Write to Selected Update Respective
+#define POWER               0x04
+#define CLR                 0x05     // Clear Code Register
+#define WRITE_LDAC_REG      0x06
+#define RESET               0x07     // Software Reset DAC8568
+#define SETUP_INTERNAL_REF  0x08
+
+//------------------------------------------------------------- 
+
+#define _DISABLE            0
+#define _ENABLE             1
+
+#define GATE1               0
+#define GATE2               1
+#define GATE3               2
+#define GATE4               3
+#define GATEALL             4
+
+//------------------------------------------------------------- 
+// Beats (Note values)
+
+#define N1ST                1   // whole
+#define N2ND                2   // harf
+#define N4TH                4   // quarter
+#define N8TH                8
+#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 NRESET              0   // Gate Reset
+
+//-------------------------------------------------------------
+// Functions
+
+inline void NetPoll(void);
+void InitOSCCV(void);
+inline void Seq(void);
+inline void UpdateCV(int, int, const unsigned int*);
+inline int UpdateTrigger(volatile bool);
+inline int UpdateGate(int, int, int, int, bool);
+inline void SetCV(void);
+inline void SetSCV(void);
+inline void ShiftCV(int);
+inline void SeqCV(int);
+void CheckModeSW(void);
+inline void CVMeter(int, const unsigned int*);
+void LCD();
+void WriteCustomChar(unsigned char, unsigned char*);
+int  SetupEthNetIf(void);
+inline void onUDPSocketEvent(UDPSocketEvent);
+
+//-------------------------------------------------------------
+// Silentway Calibration Data Mapping
+// http://www.expert-sleepers.co.uk/silentway.html
+
+//  Chromatic Scale
+const float calibMap1[QUAN_RES1] = {
+0.00559238,   0.01324014,   0.02088790,   0.02853566,   0.03618342, 
+0.04383118,   0.05147894,   0.05912671,   0.06677447,   0.07442223, 
+0.08206999,   0.08971775,   0.09736551,   0.10501327,   0.11266103, 
+0.12030879,   0.12775089,   0.13486665,   0.14198242,   0.14909819, 
+0.15621395,   0.16332972,   0.17044549,   0.17756125,   0.18467702, 
+0.19179279,   0.19890857,   0.20602433,   0.21314010,   0.22025587, 
+0.22737163,   0.23448740,   0.24160317,   0.24871893,   0.25587305, 
+0.26303557,   0.27019811,   0.27736065,   0.28452319,   0.29168573, 
+0.29884824,   0.30601078,   0.31317332,   0.32033587,   0.32749838, 
+0.33466092,   0.34182346,   0.34898600,   0.35614854,   0.36331105, 
+0.37047359,   0.37764084,   0.38481620,   0.39199156,   0.39916691, 
+0.40634227,   0.41351759,   0.42069295,   0.42786831,   0.43504366, 
+0.44221902,   0.44939438,   0.45656973,   0.46374506,   0.47092041, 
+0.47809577,   0.48527113,   0.49244648,   0.49962184,   0.50685716, 
+0.51409578,   0.52133441,   0.52857304,   0.53581166,   0.54305035, 
+0.55028898,   0.55752760,   0.56476623,   0.57200485,   0.57924354, 
+0.58648217,   0.59372079,   0.60095942,   0.60819805,   0.61543667, 
+0.62267536,   0.62996829,   0.63728690,   0.64460552,   0.65192413, 
+0.65924275,   0.66656137,   0.67387998,   0.68119860,   0.68851727, 
+0.69583589,   0.70315450,   0.71047312,   0.71779174,   0.72511035, 
+0.73242897,   0.73974758,   0.74706620,   0.75810421,   0.77163076, 
+0.78515732,   0.79868382,   0.81221038,   0.82573694,   0.83926344, 
+0.85279000,   0.86631656,   0.88188213,   0.90110368,   0.92032516
+};
+
+//  Major Scale
+const float calibMap2[QUAN_RES2] = {
+0.01324014,   0.02853566,   0.03618342,   0.05147894,   0.06677447,
+0.08206999,   0.08971775,   0.10501327,   0.12030879,   0.12775089,
+0.14198242,   0.15621395,   0.17044549,   0.17756125,   0.19179279,
+0.20602433,   0.21314010,   0.22737163,   0.24160317,   0.25587305,
+0.26303557,   0.27736065,   0.29168573,   0.29884824,   0.31317332,
+0.32749838,   0.34182346,   0.34898600,   0.36331105,   0.37764084,
+0.38481620,   0.39916691,   0.41351759,   0.42786831,   0.43504366,
+0.44939438,   0.46374506,   0.47092041,   0.48527113,   0.49962184,
+0.51409578,   0.52133441,   0.53581166,   0.55028898,   0.55752760,
+0.57200485,   0.58648217,   0.60095942,   0.60819805,   0.62267536,
+0.63728690,   0.64460552,   0.65924275,   0.67387998,   0.68851727,
+0.69583589,   0.71047312,   0.72511035,   0.73242897,   0.74706620,
+0.77163076,   0.79868382,   0.81221038,   0.83926344,   0.86631656,
+0.88188213,   0.92032516
+};
+
+//  M7(9)
+const float calibMap3[QUAN_RES3] = {
+0.02853566,   0.05147894,   0.08206999,   0.08971775,   0.12030879,
+0.14198242,   0.17044549,   0.17756125,   0.20602433,   0.22737163,
+0.25587305,   0.26303557,   0.29168573,   0.31317332,   0.34182346,
+0.34898600,   0.37764084,   0.39916691,   0.42786831,   0.43504366,
+0.44939438,   0.46374506,   0.48527113,   0.51409578,   0.52133441,
+0.55028898,   0.57200485,   0.60095942,   0.60819805,   0.62267536,
+0.63728690,   0.65924275,   0.68851727,   0.69583589,   0.72511035,
+0.74706620,   0.79868382,   0.86631656,   0.92032516
+};
+
+//  m7(9)
+const float calibMap4[QUAN_RES4] = {
+0.01324014,   0.02088790,   0.03618342,   0.05147894,   0.07442223,
+0.08971775,   0.11266103,   0.14198242,   0.16332972,   0.17756125,
+0.19890857,   0.22737163,   0.24160317,   0.24871893,   0.26303557,
+0.29168573,   0.31317332,   0.33466092,   0.34898600,   0.36331105,
+0.37047359,   0.38481620,   0.39916691,   0.41351759,   0.42069295,
+0.43504366,   0.45656973,   0.48527113,   0.50685716,   0.52133441,
+0.53581166,   0.55752760,   0.57200485,   0.59372079,   0.62267536,
+0.62996829,   0.64460552,   0.65924275,   0.68119860,   0.69583589,
+0.71779174,   0.74706620,   0.77163076,   0.78515732,   0.81221038,
+0.83926344,   0.85279000,   0.92032516
+};
+
+//  Dorian Scale
+const float calibMap5[QUAN_RES5] = {
+0.01324014,   0.02853566,   0.04383118,    0.05147894,   0.06677447,
+0.08206999,   0.08971775,   0.10501327,    0.12030879,   0.13486665,
+0.14198242,   0.15621395,   0.17044549,    0.17756125,   0.19179279,
+0.20602433,   0.22025587,   0.22737163,    0.24160317,   0.25587305,
+0.26303557,   0.27736065,   0.29168573,    0.30601078,   0.31317332,
+0.32749838,   0.34182346,   0.34898600,    0.36331105,   0.37764084,
+0.39199156,   0.39916691,   0.41351759,    0.42786831,   0.43504366,
+0.44939438,   0.46374506,   0.47809577,    0.48527113,   0.49962184,
+0.51409578,   0.52133441,   0.53581166,    0.55028898,   0.56476623,
+0.57200485,   0.58648217,   0.60095942,    0.60819805,   0.62267536,
+0.63728690,   0.65192413,   0.65924275,    0.67387998,   0.68851727,
+0.69583589,   0.71047312,   0.72511035,    0.73974758,   0.74706620,
+0.77163076,   0.79868382,   0.81221038,    0.83926344,   0.86631656,
+0.90110368,   0.92032516
+};
+
+//  Minor Scale
+const float calibMap6[QUAN_RES6] = {
+0.01324014,   0.02088790,   0.03618342,   0.05147894,   0.05912671,
+0.07442223,   0.08971775,   0.10501327,   0.11266103,   0.12775089,
+0.14198242,   0.14909819,   0.16332972,   0.17756125,   0.19179279,
+0.19890857,   0.21314010,   0.22737163,   0.23448740,   0.24871893,
+0.26303557,   0.27736065,   0.28452319,   0.29884824,   0.31317332,
+0.32033587,   0.33466092,   0.34898600,   0.36331105,   0.37047359,
+0.38481620,   0.39916691,   0.40634227,   0.42069295,   0.43504366,
+0.44939438,   0.45656973,   0.47092041,   0.48527113,   0.49244648,
+0.50685716,   0.52133441,   0.53581166,   0.54305035,   0.55752760,
+0.57200485,   0.57924354,   0.59372079,   0.60819805,   0.62267536,
+0.62996829,   0.64460552,   0.65924275,   0.66656137,   0.68119860,
+0.69583589,   0.71047312,   0.71779174,   0.73242897,   0.74706620,
+0.75810421,   0.78515732,   0.81221038,   0.83926344,   0.85279000,
+0.88188213,   0.92032516
+};
+
+//  5th
+const float calibMap7[QUAN_RES7] = {
+0.01324014,  0.06677447,   0.12030879,    0.17044549,    0.22025587,
+0.27019811,  0.32033587,   0.37047359,    0.42069295,    0.47092041,
+0.52133441,  0.57200485,   0.62267536,    0.67387998,    0.72511035,
+0.79868382,  0.90110368
+};
+
+//  Whole tone
+const float calibMap8[QUAN_RES8] = {
+0.01324014,   0.02853566,   0.04383118,   0.05912671,    0.07442223,
+0.08971775,   0.10501327,   0.12030879,   0.13486665,    0.14909819,
+0.16332972,   0.17756125,   0.19179279,   0.20602433,    0.22025587,
+0.23448740,   0.24871893,   0.26303557,   0.27736065,    0.29168573,
+0.30601078,   0.32033587,   0.33466092,   0.34898600,    0.36331105,
+0.37764084,   0.39199156,   0.40634227,   0.42069295,    0.43504366,
+0.44939438,   0.46374506,   0.47809577,   0.49244648,    0.50685716,
+0.52133441,   0.53581166,   0.55028898,   0.56476623,    0.57924354,
+0.59372079,   0.60819805,   0.62267536,   0.63728690,    0.65192413,
+0.66656137,   0.68119860,   0.69583589,   0.71047312,    0.72511035,
+0.73974758,   0.75810421,   0.78515732,   0.81221038,    0.83926344,
+0.86631656,   0.90110368
+};
+
+//-------------------------------------------------------------
+// CV Meter Custom Character
+
+unsigned char str1[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F};
+unsigned char str2[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x1F};
+unsigned char str3[8] = {0x00,0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F};
+unsigned char str4[8] = {0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F};
+unsigned char str5[8] = {0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F,0x1F};
+unsigned char str6[8] = {0x00,0x00,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F};
+unsigned char str7[8] = {0x00,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F};
+unsigned char str8[8] = {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F};
+
+//-------------------------------------------------------------
+// Global Variables
+
+float   gOSC_cv[8];
+float   gSeq_cv1[8], gSeq_cv2[8];
+float   gGlide;
+volatile int gMode;
+
+// Variables for Control
+
+float         gCtrl[3];
+volatile bool gCtrlSW[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] = {p21, p22, p23, p24};   // GateOut
+DigitalOut  gLEDS[4] = {p18, p19, p20, p28};    // LED
+DigitalOut  gCLOCKOUT(p25);                     // ClockOut
+
+AnalogIn    gAIN(p17);  // Glide Potentiometer
+InterruptIn gSW(p30);   // Mode SW
+
+Timer       gTimer;     // Timer
+Ticker      gPoller;    // Ticker Polling
+
+// Ethernet
+EthernetNetIf   gEth;
+UDPSocket       gUdp;
+
+//-------------------------------------------------------------
+// main
+ 
+int main() 
+{ 
+    float pot, _pot;
+    
+//http://mbed.org/forum/mbed/topic/229/?page=2#comment-13047    
+//Clock Up 100Mhz -------------------------------------------------------------
+    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   = 0x00020031;       /* configure PLL0                  */
+    LPC_SC->PLL0FEED  = 0xAA;             /* divide by 3 then multiply by 50 */
+    LPC_SC->PLL0FEED  = 0x55;             /* PLL0 frequency = 400,000,000    */
+ 
+    LPC_SC->PLL0CON   = 0x01;             /* PLL0 Enable                     */
+    LPC_SC->PLL0FEED  = 0xAA;
+    LPC_SC->PLL0FEED  = 0x55;
+    while (!(LPC_SC->PLL0STAT & (1<<26)));/* Wait for PLOCK0                 */
+ 
+    LPC_SC->PLL0CON   = 0x03;             /* PLL0 Enable & Connect           */
+    LPC_SC->PLL0FEED  = 0xAA;
+    LPC_SC->PLL0FEED  = 0x55;
+    while (!(LPC_SC->PLL0STAT & ((1<<25) | (1<<24))));/* Wait for PLLC0_STAT & PLLE0_STAT */
+    
+    SystemCoreClockUpdate();
+//-----------------------------------------------------------------------------
+    
+    if(SetupEthNetIf() == -1)
+    {
+        for(int i = 0; i < 4; i++) 
+        {
+            gLEDS[i] = 1;
+            wait(0.25);
+        }
+        
+        return -1;
+    }
+    
+// mdns (Bonjour)
+    HTTPServer svr;
+    mDNSResponder mdns;
+    
+    svr.addHandler<SimpleHandler>("/");
+    svr.bind(INPUT_PORT);
+    IpAddr ip = gEth.getIp();
+    mdns.announce(ip, "OSCtoCV", "_osc._udp", INPUT_PORT, "mbed(OSCtoCV)", (char *[]) {"path=/",NULL});
+    
+    InitOSCCV();
+    
+    pot = _pot = 0;
+    gGlide = gMode = 0;
+        
+    LCD();
+    gLCD.locate( 0, 1 );
+    gLCD.printf("12345678 G>>%3.2f", gGlide);
+    
+// loop
+    while(1) 
+    {
+        gGlide = pot = gAIN.read();  // Glide Value
+        
+        if(abs(pot - _pot) > 0.01f) 
+        {
+            gLCD.locate( 0, 1 );
+            gLCD.printf("12345678 G>>%3.2f", gGlide);
+            
+            _pot = gAIN.read();
+        }
+        
+        switch(gMode)
+        {               
+            case MODE_SEQ:
+                
+                Seq();
+                break;
+                                
+            case MODE_SHIF:
+            
+                ShiftCV((UpdateTrigger(gGATES[0])));
+                break;
+                    
+            case MODE_LIN:
+            
+                SetSCV();
+                break;
+            
+            default:
+            
+                SetCV();
+                break;
+        }
+    }
+}
+
+//-------------------------------------------------------------
+// Initialize OSC-CV
+
+void InitOSCCV()
+{
+// 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);
+}
+
+//-------------------------------------------------------------
+// Ethernet Polling
+
+inline void NetPoll()
+{
+    Net::poll();
+}
+
+//-------------------------------------------------------------
+// Sequencer Mode
+inline void Seq()
+{
+    static int bpm, _bpm;
+    
+    bpm = (gCtrl[0] * 300 + 10);                    // Set BPM (gCtrl[0])
+            
+    if(abs(bpm - _bpm) > 1)
+    {
+        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);
+                
+    } else if (gCtrlSW[2] && !gCtrlSW[3]) { // Sequencer Mode2 (if gCtrlSW[2] ON)
+                
+        SeqCV((UpdateGate(bpm, N16TH, GATE1, 3, false)));  // Do shift ch 1~5
+        SeqCV((UpdateGate(bpm, N4TH, GATE2, 3, false)));   // Do shift  ch 6
+        SeqCV((UpdateGate(bpm, NDOT4, GATE3, 3, false)));  // Do shift  ch 7
+        SeqCV((UpdateGate(bpm, TRIP8, GATE4, 3, false)));  // Do shift ch 8
+                
+    } else if (gCtrlSW[3]) {                        // Sequencer Mode3 (if gCtrlSW[3] ON)
+                                                        // (ch6,7,8, short loop)
+        SeqCV((UpdateGate(bpm, N16TH, GATE1, 3, false)));  // Do shift ch 1~5
+        SeqCV((UpdateGate(bpm, N8TH, GATE2, 3, false)));   // Do shift  ch 6
+        SeqCV((UpdateGate(bpm, NDOT8, GATE3, 3, false)));  // Do shift  ch 7
+        SeqCV((UpdateGate(bpm, TRIP4, GATE4, 3, false)));  // Do shift ch 8
+    }
+}
+
+//-------------------------------------------------------------
+// SPI Transfer
+// DAC8568 data word length 32bit (8bit shift out)
+
+inline void UpdateCV(int control, int address, const unsigned int *data)
+{
+
+    switch(control)
+    {
+        case WRITE_UPDATE_N:
+
+            gSYNCMODE = _DISABLE;
+            gSPI.write(00000000|control);            // padding at beginning of byte and control bits
+            gSPI.write(address << 4 | *data >> 12);  // address(ch) bits
+            gSPI.write((*data << 4) >> 8);           // middle 8 bits of data
+            gSPI.write((*data << 12) >> 8 | 00001111);
+            gSYNCMODE = _ENABLE;
+            gLDAC = _DISABLE;
+            gLDAC = _ENABLE;
+            break;
+
+        case RESET:
+
+            gSYNCMODE = _DISABLE;
+            gSPI.write(00000111);   // Software RESET
+            gSPI.write(00000000);
+            gSPI.write(00000000);
+            gSPI.write(00000000);
+            gSYNCMODE = _ENABLE;
+            break;
+
+        case CLR:
+        
+            gSYNCMODE = _DISABLE;
+            gSPI.write(00000101);   // CLR Register
+            gSPI.write(00000000);
+            gSPI.write(00000000);
+            gSPI.write(00000011);   // Ignore CLR Pin
+            gSYNCMODE = _ENABLE;
+            break;
+    }
+}
+
+//-------------------------------------------------------------
+// UpdateTrigger
+
+inline int UpdateTrigger(bool gate)
+{
+    static bool clkstate;
+    static int gatetime, oldgatetime;
+    static int oldshift;
+    
+    int time = gTimer.read_ms();
+    
+    if(gate && !clkstate)
+    {
+        oldgatetime = time;
+        clkstate = 1;
+        
+    } else if (!gate && clkstate) {
+            
+        gatetime = time - oldgatetime + 2;
+        clkstate = 0;
+        
+    } else if (gCtrlSW[0]) {
+        
+        gTimer.reset();
+        oldshift = clkstate = 0;
+    }
+        
+    if(time >= oldshift + gatetime)
+    {
+        oldshift = time;
+        return 1;
+        
+    } else {
+            
+        return 0;   
+    }
+}
+
+//-------------------------------------------------------------
+// GateOutSequence  beat(Note values) length(Gate time) invert(invert Gate)
+
+inline int UpdateGate(int bpm, int beat, int ch, int length, bool invert)
+{
+    int i;
+    static int gatetime[4], oldgatetime[4];
+    static int bar, sync24, oldsynctime;
+    
+    int time = gTimer.read_us();
+    
+    bar = (60.0f / bpm) * 4000000;
+    sync24 = (bar / 4) / 24; // sync24 not tested
+    
+    switch(beat)                                // Calculate Note values 
+        {
+            case NDOT2:
+                
+                gatetime[ch] = (bar / 4) * 3;
+                break;
+                    
+            case NDOT4:
+            
+                gatetime[ch] = (bar / 8) * 3;
+                break;
+                
+            case NDOT8:
+                
+                gatetime[ch] = (bar / 16) * 3;
+                break;
+                    
+            case NDOT16:
+                
+                gatetime[ch] = (bar / 32) * 3;
+                break;
+        
+            case NDOT32:
+                
+                gatetime[ch] = (bar / 64) * 3;
+                break;
+                
+            case TRIP2:
+                
+                gatetime[ch] = bar / 3;
+                break;
+                
+            case TRIP4:
+                
+                gatetime[ch] = (bar / 2) / 3;
+                break;
+                
+            case TRIP8:
+                        
+                gatetime[ch] = (bar / 4) / 3;
+                break;
+            
+            case TRIP16:
+                
+                gatetime[ch] = (bar / 8) / 3;
+                break;
+            
+            case TRIP32:
+                
+                gatetime[ch] = (bar / 16) / 3;
+                break;
+                
+            case NRESET:
+                
+                for(i = 0; i < GATEALL; ++i)    // Reset
+                {
+                    gTimer.reset();
+                    oldsynctime = oldgatetime[i] = gatetime[i] = NRESET;
+                }
+                break;
+                
+            default:
+                
+                gatetime[ch] = bar / beat;
+        }
+        
+        if(time > oldsynctime + sync24)  // sync24 not tested
+        {
+            oldsynctime = time;
+            gCLOCKOUT = 1;
+            
+        } else if (time > sync24 - (sync24 - 2)) {
+        
+            gCLOCKOUT = 0;
+        }
+    
+    if (ch == GATEALL) 
+    {
+        return -1;
+        
+    } else if (time > oldgatetime[ch] + gatetime[ch] && !invert) {
+        
+        oldgatetime[ch] = time;
+        gLEDS[ch] = gGATES[ch] = 1;
+        
+        return ch + 1;
+    
+    } else if (time > oldgatetime[ch] + gatetime[ch] && invert) {
+        
+        oldgatetime[ch] = time;
+        gLEDS[ch] = gGATES[ch] = 0;
+        
+        return 0;
+        
+    } else if (time > oldgatetime[ch] + (gatetime[ch] - gatetime[ch] / length) && !invert) {
+        
+        gLEDS[ch] = gGATES[ch] = 0;
+        
+        return 0;
+        
+    } else if (time > oldgatetime[ch] + (gatetime[ch] - gatetime[ch] / length) && invert) {
+        
+        gLEDS[ch] = gGATES[ch] = 1;
+        
+        return ch + 1;
+        
+    } else {
+        
+        return -1;          
+    }
+}
+
+//-------------------------------------------------------------
+// Calculate CV
+
+inline void SetCV()
+{
+    static int ch, quan;
+    static float glidecv[8], oldcv[8];
+    unsigned int cv[8];
+    float qcv;
+
+    switch(gMode) 
+        {
+            case MODE_LIN:
+                
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + gOSC_cv[ch] * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                    
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+                    
+            case MODE_QChr:
+            
+                quan = 40616 / QUAN_RES1;
+                qcv = calibMap1[(unsigned int)(gOSC_cv[ch] / quan)];
+                    
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+                
+            case MODE_QMaj:
+                
+                quan = 40616 / QUAN_RES2;
+                qcv = calibMap2[(unsigned int)(gOSC_cv[ch] / quan)];
+                    
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+                    
+            case MODE_QDor:
+                
+                quan = 40616 / QUAN_RES5;
+                qcv = calibMap5[(unsigned int)(gOSC_cv[ch] / quan)];
+                    
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+                
+            case MODE_Q5th:
+                
+                quan = 40616 / QUAN_RES7;
+                qcv = calibMap7[(unsigned int)(gOSC_cv[ch] / quan)];
+                    
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+                
+            case MODE_QWht:
+                
+                quan = 40616 / QUAN_RES8;
+                qcv = calibMap8[(unsigned int)(gOSC_cv[ch] / quan)];
+                    
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+                
+            case MODE_Calb:
+                
+                cv[ch] = 19212;     // A880.0Hz
+                
+                gGATES[0] = gGATES[1] = gGATES[2] = gGATES[3] = 1;
+                gLEDS[0] = gLEDS[1] = gLEDS[2] = gLEDS[3] = 1;
+                
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+        }
+
+        CVMeter(ch, &cv[ch]);
+        
+        ch++;
+        ch &= 0x07;
+}
+
+//-------------------------------------------------------------
+// Calculate CV
+
+inline void SetSCV()
+{
+    static int ch, quan, mode;
+    static float glidecv[8], oldcv[8];
+    unsigned int cv[8];
+    float qcv;
+
+    mode = (gCtrl[1] * 8);
+
+    gCLOCKOUT = gGATES[0];
+    
+    switch(mode) 
+        {
+            case Lin:
+                
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + gOSC_cv[ch] * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                    
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+                    
+            case Chr:
+            
+                quan = 40616 / QUAN_RES1;
+                qcv = calibMap1[(unsigned int)(gOSC_cv[ch] / quan)];
+                    
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+                
+            case Maj:
+                
+                quan = 40616 / QUAN_RES2;
+                qcv = calibMap2[(unsigned int)(gOSC_cv[ch] / quan)];
+                    
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+            
+            case M7:
+            
+                quan = 40616 / QUAN_RES3;
+                qcv = calibMap3[(unsigned int)(gOSC_cv[ch] / quan)];
+                    
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+                
+            case Min7:
+                
+                quan = 40616 / QUAN_RES4;
+                qcv = calibMap4[(unsigned int)(gOSC_cv[ch] / quan)];
+                    
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+                    
+            case Dor:
+                
+                quan = 40616 / QUAN_RES5;
+                qcv = calibMap5[(unsigned int)(gOSC_cv[ch] / quan)];
+                    
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+        
+            case Min:
+                
+                quan = 40616 / QUAN_RES6;
+                qcv = calibMap6[(unsigned int)(gOSC_cv[ch] / quan)];
+                    
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+                
+            case S5th:
+                
+                quan = 40616 / QUAN_RES7;
+                qcv = calibMap7[(unsigned int)(gOSC_cv[ch] / quan)];
+                    
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+                
+            case Wht:
+                
+                quan = 40616 / QUAN_RES8;
+                qcv = calibMap8[(unsigned int)(gOSC_cv[ch] / quan)];
+                    
+                oldcv[ch] = glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide);
+                cv[ch] = (unsigned int)glidecv[ch];
+                        
+                UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]);
+                break;
+        }
+
+        CVMeter(ch, &cv[ch]);
+        
+        ch++;
+        ch &= 0x07;
+}
+
+//-------------------------------------------------------------
+// Sequence & Shift Out CV
+
+inline void SeqCV(int shift)
+{
+    int i, j, k;
+    static int ch, quan, mode;
+    static int cnt1, cnt2, cnt3;
+    static int cntloop1, cntloop2, cntloop3;
+    static float glidecv[8], shiftcv[8];
+    static float buffercv[9], loopcv[3];
+    unsigned int cv[8];
+    float qcv;
+        
+    mode = (gCtrl[1] * 8);  // Sequencer Quantize Mode (gCtrl[1])
+    
+    switch(mode) 
+        {
+            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);
+                }
+                
+                cv[0] = (unsigned int)glidecv[0];
+                
+                UpdateCV(WRITE_UPDATE_N, 0, &cv[0]);
+                break;
+                    
+            case Chr:
+            
+                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);
+                cv[0] = (unsigned int)glidecv[0];
+                
+                UpdateCV(WRITE_UPDATE_N, 0, &cv[0]);
+                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[0] = (unsigned int)glidecv[0];
+                
+                UpdateCV(WRITE_UPDATE_N, 0, &cv[0]);
+                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);
+                cv[0] = (unsigned int)glidecv[0];
+                
+                UpdateCV(WRITE_UPDATE_N, 0, &cv[0]);
+                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);
+                cv[0] = (unsigned int)glidecv[0];
+                
+                UpdateCV(WRITE_UPDATE_N, 0, &cv[0]);
+                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[0] = (unsigned int)glidecv[0];
+                
+                UpdateCV(WRITE_UPDATE_N, 0, &cv[0]);
+                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[0] = (unsigned int)glidecv[0];
+                
+                UpdateCV(WRITE_UPDATE_N, 0, &cv[0]);
+                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);
+                cv[0] = (unsigned int)glidecv[0];
+                
+                UpdateCV(WRITE_UPDATE_N, 0, &cv[0]);
+                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);
+                cv[0] = (unsigned int)glidecv[0];
+                
+                UpdateCV(WRITE_UPDATE_N, 0, &cv[0]);
+                break;
+        }
+            
+        if(!gCtrlSW[2] && !gCtrlSW[3])              // Sequencer Mode1
+        {
+            for(i = 1; i < 8; ++i)
+            {
+                glidecv[i] = glidecv[i] * gGlide + shiftcv[i] * (1.0f - gGlide);
+                cv[i] = (unsigned int)glidecv[i];
+                    
+                UpdateCV(WRITE_UPDATE_N, i, &cv[i]);
+            }
+            
+            if(shift == 1)                  // GATE1
+            {
+                for(j = 1; j < 8; ++j)      // Shift ch2~8
+                {
+                    shiftcv[j] = glidecv[j-1];
+                }
+            
+                ch++;
+                ch &= 0x0F;
+            }
+            
+            cnt1 = cnt2 = cnt3 = 0;
+                    
+        } else if (gCtrlSW[2] && !gCtrlSW[3]) { // Sequencer Mode2
+                
+            for(i = 1; i < 8; ++i)
+            {
+                glidecv[i] = glidecv[i] * gGlide + shiftcv[i] * (1.0f - gGlide);
+                cv[i] = (unsigned int)glidecv[i];
+                    
+                UpdateCV(WRITE_UPDATE_N, i, &cv[i]);
+            }
+            
+            if(shift == 1)                      // GATE1
+            {
+                for(j = 1; j < 5; ++j)
+                {
+                    shiftcv[j] = glidecv[j-1];  // Shift ch2~5
+                }
+            
+                ch++;
+                ch &= 0x0F;
+                
+            } else if (shift == 2) {            // GATE2
+                
+                shiftcv[5] = glidecv[1];        // Shift ch6
+                
+            } else if (shift == 3) {            // GATE3
+                
+                shiftcv[6] = glidecv[2];        // Shift ch7
+                
+            } else if (shift == 4) {            // GATE4
+                
+                shiftcv[7] = glidecv[3];        // Shift ch8
+            }
+            
+            cnt1 = cnt2 = cnt3 = 0;
+                
+        } else if (gCtrlSW[3]) {                        // Sequencer Mode3
+                
+            for(i = 1; i < 5; ++i)
+            {
+                glidecv[i] = glidecv[i] * gGlide + shiftcv[i] * (1.0f - gGlide);
+                cv[i] = (unsigned int)glidecv[i];
+                    
+                UpdateCV(WRITE_UPDATE_N, i, &cv[i]);            
+            }
+            
+            for(j = 5; j < 8; ++j)
+            {
+                glidecv[j] = glidecv[j] * gGlide + loopcv[j - 5] * (1.0f - gGlide);
+                cv[j] = (unsigned int)glidecv[j];
+                    
+                UpdateCV(WRITE_UPDATE_N, j, &cv[j]);            
+            }
+            
+            if(shift == 1)                      // GATE1
+            {
+                for(k = 1; k < 8; ++k)
+                {
+                    shiftcv[k] = glidecv[k-1];  // Shift ch2~5
+                }
+            
+                ch++;
+                ch &= 0x0F;
+                
+            } else if (shift == 2) {            // GATE2
+                
+                if(cnt1 < 4) 
+                {
+                    loopcv[0] = buffercv[cnt1] = shiftcv[4];
+                    
+                    cnt1++;
+                    
+                } else if (cnt1 >= 4) {
+                    
+                    loopcv[0] = buffercv[cntloop1];
+                    
+                    cntloop1++;
+                    cntloop1 &= 0x03;
+                }
+                        
+            } else if (shift == 3) {            // GATE3
+                
+                if(cnt2 < 3) 
+                {
+                    loopcv[1] = buffercv[(cnt2 + 4)] = shiftcv[5];
+                    
+                    cnt2++;
+                    
+                } else if (cnt2 >= 3) {
+                    
+                    loopcv[1] = buffercv[(cntloop2 + 4)];
+                    
+                    cntloop2++;
+                    cntloop2 &= 0x03;   
+                }
+                
+            } else if (shift == 4) {            // GATE4
+                
+                if(cnt3 < 2) 
+                {
+                    loopcv[2] = buffercv[(cnt3 + 7)] = shiftcv[6];
+                    
+                    cnt3++;
+                    
+                } else if (cnt3 >= 2) {
+                    
+                    loopcv[2] = buffercv[(cntloop3 + 7)];
+                    
+                    cntloop3++;
+                    cntloop3 &= 0x01;   
+                }
+            }
+            
+            if(gCtrlSW[1])                  // Update loop buffer (if gCtrlSW[1] ON)
+            {
+                cnt1 = cnt2 = cnt3 = 0;
+            } 
+        }
+        
+        if(ch < 8)
+        {
+            CVMeter(ch, &cv[0]);
+                            
+        } else {
+                        
+            CVMeter((ch-8), &cv[0]);
+        }
+}
+
+//-------------------------------------------------------------
+// Shift CV
+
+inline void ShiftCV(int shift)
+{
+    int i;
+    static int ch;
+    static float glidecv[8], shiftcv[8], oldcv;
+    unsigned int cv[8];
+    
+    gLEDS[1] = gGATES[1] = gGATES[0];
+    
+    oldcv = glidecv[0] = glidecv[0] * gGlide + gOSC_cv[0] * (1.0f - gGlide);
+    
+    cv[0] = (unsigned int)glidecv[0];
+                
+    UpdateCV(WRITE_UPDATE_N, 0, &cv[0]);
+    
+    glidecv[ch+1] = glidecv[ch+1] * gGlide + shiftcv[ch+1] * (1.0f - gGlide);
+    cv[ch+1] = (unsigned int)glidecv[ch+1];
+                    
+    UpdateCV(WRITE_UPDATE_N, ch+1, &cv[ch+1]);
+                
+    if(shift == 1)              // GATE1
+    {   
+        shiftcv[0] = oldcv;
+        
+        for(i = 7; i > 0; --i)
+        {
+            shiftcv[i] = shiftcv[i-1];
+        }
+    }
+        
+    if(ch < 8)
+    {
+        CVMeter(ch, &cv[0]);
+                            
+    } else {
+                        
+        CVMeter((ch-8), &cv[0]);
+    }
+    
+    ch++;
+    ch &= 0x07;
+}
+
+//-------------------------------------------------------------
+// Check SW
+
+void CheckModeSW()
+{   
+    wait(0.05);
+    
+    if(gMode < MODE_NUM - 1) 
+    {   
+        gMode++;
+            
+    } else {
+                
+        gMode = 0;
+    }
+    
+    gCLOCKOUT = gGATES[0] = gGATES[1] = gGATES[2] = gGATES[3] = 0;
+    gLEDS[0] = gLEDS[1] = gLEDS[2] = gLEDS[3] = 0;
+    
+    if((gMode == MODE_SEQ) || (gMode == MODE_SHIF))
+    {
+        gTimer.start();     // Sequencer Timer Start
+        
+    } else {
+            
+        gTimer.stop();      // Sequencer Timer Stop
+    }
+    
+    LCD();
+}
+
+//-------------------------------------------------------------
+// CV meter
+
+inline void CVMeter(int ch, const unsigned int *level)
+{
+    int cvmeter;
+    
+    cvmeter = *level / (SCALING_N / 7.9f);
+        
+    gLCD.locate ( ch, 0 );
+    gLCD.putc(cvmeter);     // put custom char
+}
+
+//-------------------------------------------------------------
+// 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_QChr:
+                gLCD.locate( 9, 0 );
+                gLCD.printf("QUAN_C ");
+                break;
+                
+            case MODE_QMaj: 
+                gLCD.locate( 9, 0 );
+                gLCD.printf("QUAN_M ");
+                break;
+                    
+            case MODE_QDor: 
+                gLCD.locate( 9, 0 );
+                gLCD.printf("QUAN_D ");
+                break;
+                
+            case MODE_Q5th: 
+                gLCD.locate( 9, 0 );
+                gLCD.printf("QUAN_5 "); 
+                break;
+                    
+            case MODE_QWht: 
+                gLCD.locate( 9, 0 );
+                gLCD.printf("QUAN_W "); 
+                break;
+                
+            case MODE_SEQ:  
+                gLCD.locate( 9, 0 );
+                gLCD.printf("ASRSEQ ");
+                break;
+                
+            case MODE_SHIF: 
+                gLCD.locate( 9, 0 );
+                gLCD.printf("ASHSEQ ");
+                break;
+        }
+}
+
+//-------------------------------------------------------------
+// Write command Custom Char LCD CGRAM(CV Meter) 
+
+void WriteCustomChar(unsigned char addr, unsigned char *c)
+{   
+    char cnt = 0;
+    addr = ((addr << 3) | 0x40);
+    
+    while(cnt < 0x08)
+    {
+        gLCD.writeCommand(addr | cnt);
+        gLCD.writeData(*c);
+        
+        cnt++;
+        c++;
+    }
+}
+
+//-------------------------------------------------------------
+// Setup Ethernet port
+
+int SetupEthNetIf()
+{
+    gLCD.locate( 0, 1 );
+    gLCD.printf("Setting up...   ");
+//  printf("Setting up...\r\n");
+    EthernetErr ethErr = gEth.setup();
+    
+    if(ethErr)
+    {
+        gLCD.locate( 0, 1 );
+        gLCD.printf("Error in setup.");
+//  printf("Error %d in setup.\r\n", ethErr);
+        return -1;
+    }
+//  printf("Setup OK\r\n");
+ 
+//  printf("IP address %d.%d.%d.%d\r\n", gEth.getIp()[0], gEth.getIp()[1], gEth.getIp()[2], gEth.getIp()[3]);
+    Host broadcast(IpAddr(gEth.getIp()[0], gEth.getIp()[1], gEth.getIp()[2], 255), INPUT_PORT, NULL);
+    gUdp.setOnEvent(&onUDPSocketEvent);
+    gUdp.bind(broadcast);
+    
+    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;
+}
+
+//-------------------------------------------------------------
+// Handller receive UDP Packet
+
+inline void onUDPSocketEvent(UDPSocketEvent e)
+{
+    union OSCarg msg[10];
+    char buf[768] = {0};
+    int num, recvlen, len;
+    unsigned int absv;
+    int messagepos = 0;
+    bool bundleflag = false;
+    
+    Host host;
+    
+    switch(e)
+    {
+        case UDPSOCKET_READABLE: // The only event for now
+        
+        recvlen = gUdp.recvfrom(buf, 768, &host);  // packet length    
+        
+        if(recvlen <= 0)  break;
+        
+        if(buf[0] == '#') // #bundle
+        {
+            messagepos += 16;     // skip #bundle & timetag
+            recvlen -= 16;
+            
+            bundleflag = true;  
+        }
+        
+        do {
+                if(bundleflag)
+                {
+                    messagepos += 4;
+                    recvlen -= 4;
+                    
+                    if(recvlen <= 0)
+                    {
+                        bundleflag = false;
+                        break;
+                    }
+                }
+                
+                if(getOSCmsg(buf + messagepos, msg) == -1)  continue;
+            
+                len = strlen(msg[0].address);
+        
+                if(isdigit(msg[0].address[len-1])) 
+                {       
+                    num = msg[0].address[len-1] - '0' - 1;
+            
+                } else {
+            
+                    num = -1;
+                }
+        
+                absv = msg[2].f + 0; //convert -0 to 0
+        
+            // address pattern SYNC & GATE (Type Tag int, float)
+                if(!strncmp(msg[0].address+(len-1)-4, "sync", 4)) 
+                { 
+                    if(absv >= 1 || msg[2].i >= 1) gCLOCKOUT = 1;
+                    else                           gCLOCKOUT = 0;
+                    continue;
+
+                } else if (!strncmp(msg[0].address+(len-1)-4, "gate", 4) && (num != -1)) {
+                    if(num > 4) continue;
+                    if(absv >= 1 || msg[2].i >= 1) gLEDS[num] = gGATES[num] = 1;
+                    else                           gLEDS[num] = gGATES[num] = 0;
+                    continue;
+            // (touchOSC Control push, toggle)
+                } else if (!strncmp(msg[0].address+(len-1)-4, "push", 4) && (num != -1)) {     
+                    if(num > 4) continue;
+                    if(absv >= 1 || msg[2].i >= 1) 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(absv >= 1 || msg[2].i >= 1) 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(absv >= 1 || msg[2].i >= 1) 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);
+                    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);
+                    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);
+                    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);
+                    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 > 4) continue;
+                    if(absv >= 1 || msg[2].i >= 1) gCtrlSW[num] = true;
+                    else                           gCtrlSW[num] = false;
+                    continue;
+                                                
+                } else if (!strncmp(msg[0].address+(len-1)-4, "ctrl", 4) && (num != -1)) {
+                    if(num > 3) continue;                                             
+                    if(msg[1].typeTag[1] == 'f') gCtrl[num] = msg[2].f;
+                    continue;
+                }
+                
+            } while(bundleflag);
+                    
+    }
+}