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

main.cpp

Committer:
casiotone401
Date:
2016-05-26
Revision:
31:0595b7456780
Parent:
29:8b61b87b9676

File content as of revision 31:0595b7456780:

//-------------------------------------------------------------
//                  TI DAC8568  OSCtoCV 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 "FastIO.h"
//#include "FastAnalogIn.h"
#include "DebouncedInterrupt.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 "ClockControl.h" // https://developer.mbed.org/users/JST2011/code/ClockControl/
#include "OSCtoCV.h"
#include "OSCtoCV_Sequencer.h"
#include "OSCtoCV_GateSequencer.h"
#include "OSCtoCV_Euclidean.h"
#include "OSCtoCV_Random.h"
#include "OSCtoCV_LFO.h"

#include <stdlib.h>
#include <ctype.h>
#include <math.h>

//-------------------------------------------------------------
// Macros

#define MODE_CLB            0        // Calibration (for VCO Tuning)
#define MODE_OSC            1        // Mode OSCtoCV 
#define MODE_SEQ            2        // Mode Shift Sequencer
#define MODE_185            3        // Mode M185 Sequencer
#define MODE_437            4        // Mode 437 Sequencer
#define MODE_EUC            5        // Mode Euclidean Sequencer
#define MODE_RND            6        // Mode xshift Random Generator 
#define MODE_LFO            7        // Mode Stepped LFO 

#define MODE_TOTAL          8        // Modes

//-------------------------------------------------------------
// Functions

void InitOSCCV(void);
inline void NetPoll(void);
void CalibrationCV(void);
inline void SetCV(void);
inline int CheckBPM(void);
inline float CheckGlide(void);
inline float CheckDuration(void);
void CheckModeSW(void);
inline void UpdateLCD();
void WriteCustomChar(unsigned char, unsigned char*);
int  SetupEthNetIf(void);
inline void onUDPSocketEvent(UDPSocketEvent);


//-------------------------------------------------------------
// Global Variables

// 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};

// OSCtoCV Converter Mode 
int         gMode;

// UDP Socket
UDPSocket   gUdp;

//-------------------------------------------------------------
// main
 
int main() 
{ 
    float duration;
    int bpm;
        
    InitOSCCV();

// Init LCD        
    UpdateLCD();
    
// Main loop
    while (1) 
    {
        UpdateLCD(); // Check Text LCD Mode Status
        
        CheckGlide(); // check glide value
        
        bpm = CheckBPM(); // check current BPM
        
        duration = CheckDuration(); // check current duration(Gate length)
        
        switch (gMode)
        {               
            case MODE_OSC: // OSCtoCV mode
            
                SetCV();
                break;
                
            case MODE_SEQ: // Shift Sequencer mode
            
                GateSeq(bpm, N8TH, GATE2, 3, NON_INVERT, GATESOUT_ON, SYNC_OFF);
                
                if (gCtrlSW[3])
                {   // euclid sequencer auto offset
                    ShiftCVSeq(EuclideanSeq(GateSeq(bpm, N16TH, SUBGATE, (duration * 12.0f), NON_INVERT, GATESOUT_OFF, SYNC_ON), gCtrlSW[0], GATESOUT_OFF, true), gCtrlSW[0], CV_CHANNEL8);
                
                } else {
                    
                    ShiftCVSeq(BeatsSeq(GateSeq(bpm, N16TH, SUBGATE, (duration * 8.0f), NON_INVERT, GATESOUT_OFF, SYNC_ON), gCtrlSW[0], GATESOUT_OFF), gCtrlSW[0], CV_CHANNEL8);
                }
                break;
                
            case MODE_185: // M185 Sequencer mode
            
                
                GateSeq(bpm, N8TH, GATE2, 3, NON_INVERT, GATESOUT_ON, SYNC_OFF);
                
                if (gCtrlSW[3])
                {   // euclid sequencer auto offset
                    M185Seq(EuclideanSeq(GateSeq(bpm, N16TH, SUBGATE, (duration * 12.0f), NON_INVERT, GATESOUT_OFF, SYNC_ON), gCtrlSW[0], GATESOUT_OFF, true), gCtrlSW[0], CV_CHANNEL8);
                    
                } else {
                    
                    M185Seq(BeatsSeq(GateSeq(bpm, N16TH, SUBGATE, (duration * 8.0f), NON_INVERT, GATESOUT_OFF, SYNC_ON), gCtrlSW[0], GATESOUT_OFF), gCtrlSW[0], CV_CHANNEL8);
                }
                break;
            
            case MODE_437: // F437 sequencer
                
                GateSeq(bpm, N8TH, GATE2, 3, NON_INVERT, GATESOUT_ON, SYNC_OFF);
                
                if (gCtrlSW[3])
                {   // euclid sequencer auto offset
                    PolyCVSeq(EuclideanSeq(GateSeq(bpm, N16TH, SUBGATE, (duration * 12.0f), NON_INVERT, GATESOUT_OFF, SYNC_ON), gCtrlSW[0], GATESOUT_OFF, true), gCtrlSW[0]);
                    
                } else {
                    
                    PolyCVSeq(BeatsSeq(GateSeq(bpm, N16TH, SUBGATE, (duration * 8.0f), NON_INVERT, GATESOUT_OFF, SYNC_ON), gCtrlSW[0], GATESOUT_OFF), gCtrlSW[0]);
                }
                break;
                    
            case MODE_EUC: // Euclidean Sequencer mode
            
                ShiftCVSeq(GateSeq(bpm, N1ST, SUBGATE, (duration * 5.0f), NON_INVERT, GATESOUT_OFF, SYNC_OFF), gCtrlSW[0], CV_CHANNEL8); 
                EuclideanSeq(GateSeq(bpm, N16TH, GATE1, 3, NON_INVERT, GATESOUT_OFF, SYNC_OFF), gCtrlSW[0], GATESOUT_ON, false);
                break;
            
            case MODE_RND: // Random CV Generator mode
        
                RandomCVGenerator(GateSeq(bpm, N32TH, GATE1, (duration * 5.0f), NON_INVERT, GATESOUT_OFF, SYNC_ON));
                break;

            case MODE_LFO: // Stepped LFO mode
        
                SteppedLFO(CV_CHANNEL1, false); // LFO out ch1 ~ ch8
                break;

            default:       // CV Calibration mode
                
                CalibrationCV(); 
                break;
        }
        
    }
}

//-------------------------------------------------------------
// Ethernet Polling

inline void NetPoll()
{
    Net::poll();
}

//-------------------------------------------------------------
// Initialize OSCtoCV

void InitOSCCV()
{
    
// Set System Frequency 120Mhz 
    setSystemFrequency(0x3, 0x1, 15, 1);
    wait(0.5);

// Setup Ethernet   
    SetupEthNetIf();

// Announce mdnsResponder  (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});
        
// 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

// Init Euclidean Sequencer    
    InitEuclideanSeq();    
    
// Init Glide value
    gGlide = gAIN.read();
 
// Init Mode
    gMode = MODE_CLB;

// Init Sequencer Data
    for (int i = 0; i < 16; ++i) 
    {
        if (i < 8) 
        {
            g185_cv[i] = (calibMap1[69] * SCALING_N);
            gBeatsLevel[i] = gBeatsDecay[i] = 1;    
        }
        
        gSeq_cv[i] = (calibMap1[69] * SCALING_N);
    }

// Set OSC message for sending 
    sendMes.setIp(touchOSCAddress); 
    sendMes.setPort(touchOSCPort);
    
    gSW.attach(&CheckModeSW, IRQ_RISE, 20);     // InterruptIn rising edge(ModeSW)
    wait(0.5);
    
    gPoller.attach_us(&NetPoll, POLLING_INTERVAL);  // Ticker Polling
    wait(0.2);
}

//-------------------------------------------------------------
// Calibration Mode

void CalibrationCV()
{
    static int ch;
    unsigned int cv;

    cv = (unsigned int)(calibMap1[69] * SCALING_N);  // A880.0Hz
                
    gSUBGATE = gGATES[0] = gGATES[1] = gGATES[2] = gGATES[3] = true;
    
    UpdateCV(WRITE_UPDATE_N, ch, &cv);
    UpdateCVMeter(ch, &cv);
    
    ++ch;
    ch &= 0x07;
}

//-------------------------------------------------------------
// Calculate CV

inline void SetCV()
{
    static int ch, mcount;
    static float glidecv[8];
    unsigned int cv;
    static float qcv;

    switch (CheckQuantizeMode()) 
        {
            case Lin:
                
                glidecv[ch] = glidecv[ch] * gGlide + gOSC_cv[ch] * (1.0f - gGlide);
                break;
                    
            case Chr:

                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);
                break;
                
            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);
                break;
            
            case M7:
                
                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);
                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);
                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);

                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);
                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);
                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);
                break;
        }
        
    cv = (unsigned int)glidecv[ch];
            
    UpdateCV(WRITE_UPDATE_N, ch, &cv);

    if (mcount == 0x1F) 
    {
        UpdateCVMeter(ch, &cv);
    }

    ++ch;
    
    if (ch &= 0x07)
    {
        ++mcount;
        mcount &= 0x3F;
    }
}


//-------------------------------------------------------------
// Check BPM

inline int CheckBPM()
{   
    static int _bpm = -1;
    int bpm;
    
    if (gCtrlSW[0]) 
    {
        bpm = 0;

        return bpm;
    }
    
    if (gCtrl[0]) {

        bpm = (gCtrl[0] * 240 + 5);

        if (bpm != _bpm)
        {
            _bpm = bpm;
            
            sendMes.setTopAddress("/bpm");
            sendMes.setArgs("i", bpm);
            osc.sendOsc(&sendMes);
            
            sendMes.setTopAddress("/ctrl1");
            sendMes.setArgs("f", gCtrl[0]);
            osc.sendOsc(&sendMes);
        }
    }
                        
    return bpm;
}

//-------------------------------------------------------------
// Check Glide Value

inline float CheckGlide()
{
    static float _pot;
    float pot = 0;
    
    pot = gAIN.read();  // Update glide value
        
    if (!pot) // when (glide pot value == 0) && MODE_OSC
    {         // 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 = pot;
        
        gLCD.locate( 9, 1 );
        gLCD.printf("G>>%3.2f", gGlide);
    }
    
    return pot;
}

//-------------------------------------------------------------
// Check Duration Value

inline float CheckDuration()
{
    static float _duration = 0.6f;
    
    if (_duration != gCtrl[6]) // check current gate duration
    {
        sendMes.setTopAddress("/ctrl7");
        sendMes.setArgs("f", gCtrl[6]);
        osc.sendOsc(&sendMes);
        
        _duration = gCtrl[6];
    }
    
    return gCtrl[6];    
}

//-------------------------------------------------------------
// Check Mode SW

void CheckModeSW()
{   
    if (gMode < MODE_TOTAL - 1) 
    {   
        ++gMode;
            
    } else {
                
        gMode = 0;
    }
    
    gCLOCKOUT = gGATES[0] = gGATES[1] = gGATES[2] = gGATES[3] = false;
    gSubModeCount1 = gSubModeCount2 = 0;
    
    if (gMode != MODE_CLB || gMode != MODE_OSC)
    {
        gTimer.start();     // Sequencer Timer Start
        midi.begin(1);
        
    } else {
            
        gTimer.stop();      // Sequencer Timer Stop
    }
    
}

//-------------------------------------------------------------
// Print LCD Mode Status

inline void UpdateLCD()
{
    static int _mode = -1;
    static int _qmode = -1;
    static int qmode;
    
    if (_mode != gMode)
    {
        sendMes.setTopAddress("/mode");
        
        switch (gMode) 
            {
                case MODE_CLB: 
                    gLCD.locate( 9, 0 );
                    gLCD.printf("CLB|880");
                    
                    gLCD.locate( 0, 1 );
                    gLCD.printf("12345678 G>>%3.2f", gGlide);
                    
                    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_437:  
                    gLCD.locate( 9, 0 );
                    gLCD.printf("437|");
            
                    sendMes.setArgs("s", "F437 SEQ");
            
                    break;
                        
                case MODE_EUC:  
                    gLCD.locate( 9, 0 );
                    gLCD.printf("EUC|");
                    
                    sendMes.setArgs("s", "Euclidean SEQ");
                    break;
                
                case MODE_RND:  
                    gLCD.locate( 9, 0 );
                    gLCD.printf("RND|");
                
                    sendMes.setArgs("s", "Xorshift Random");
                    break;
                    
                case MODE_LFO:  
                    gLCD.locate( 9, 0 );
                    gLCD.printf("LFO|");
                
                    sendMes.setArgs("s", "Stepped LFO");
                    break;

                default:
                    break;
            }
            
            osc.sendOsc(&sendMes);
            _mode = gMode;
    }
    
    qmode = (gCtrl[1] * (SCALE_TOTAL - 1));
    
    if (_qmode != qmode)
    {
        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;
    }

}


//-------------------------------------------------------------
// 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)
    {
        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 OSC UDP Packet

inline void onUDPSocketEvent(UDPSocketEvent e)
{
    static union OSCarg msg[10];
    static char buf[768] = {0};
    int recvlen;
    int num, numrow, len, offset;
    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 (!bundleflag && 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 = strlength(msg[0].address);

                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;
                }

                if (!strncmp(msg[0].address + (len - offset) - 4, "page", 4)) // touchOSC page
                { 
                    continue;

                } else if (!strncmp(msg[0].address + (len - offset) - 4, "sync", 4)) { 
                    if (msg[2].i != 0) gCLOCKOUT = true;
                    else              gCLOCKOUT = false;
                    continue;

                } 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 - offset) - 5, "fader", 5) && (num != -1)) {
                    if (num > 7) continue;                                              
                    gOSC_cv[num] = msg[2].f * (SCALING_N);
                    continue;

                } 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 - 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;

                } else if (!strncmp(msg[0].address + (len - offset) - 5, "m185/", 5) && (num != -1)) {
                    if (num > 7) continue;
                    if (msg[1].typeTag[1] == 'f') g185_cv[num] = msg[2].f * (SCALING_N);
                    continue;

                } 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 - 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 - 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) - 9, "g185mode/", 9) && (num != -1)) {
                    if (num > 7) continue;
                    gGateMode185[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) - 9, "slide185/", 9) && (num != -1)) {
                    if (num > 7) continue;
                    gSlide185[num] = msg[2].f;
                    continue;

                } else if (!strncmp(msg[0].address + (len - offset - 2) - 7, "accent/", 7) && (num != -1)) {

                    if (isdigit(msg[0].address[len - 3])) 
                    {       
                        num = msg[0].address[len - 3] - '0' - 1;
                    }

                    gAccent[num] = msg[2].i;
                    continue;

                } else if (!strncmp(msg[0].address + (len - offset - 3) - 7, "accent/", 7) && (num != -1)) {

                    if (isdigit(msg[0].address[len - 3]))
                    {       
                        num = msg[0].address[len - 3] - '0' - 1;

                        if (isdigit(msg[0].address[len - 4])) 
                        {
                            num += 10;
                        }
                    }

                    gAccent[num] = msg[2].i;
                    continue;

                } else if (!strncmp(msg[0].address + (len - offset - 3) - 6, "185acc/", 6) && (num != -1)) {

                    if (isdigit(msg[0].address[len-3])) 
                    {       
                        num = msg[0].address[len-3] - '0' - 1;

                        if (isdigit(msg[0].address[len - 4])) 
                        {
                            num += 10;
                        }
                    }

                    gAccent185[num] = msg[2].i;
                    continue;

                } else if (!strncmp(msg[0].address + (len - offset - 2) - 3, "bm/", 3) && (num != -1)) {

                    if (isdigit(msg[0].address[len - 3])) 
                    {       
                        num = msg[0].address[len - 3] - '0' - 1;

                        if (isdigit(msg[0].address[len - 4])) 
                        {
                            num += 10;
                        }
                    }

                    if (isdigit(msg[0].address[len - 1])) 
                    {       
                        numrow = msg[0].address[len - 1] - '0' - 1;
                    }

                    gBeatsMatrix[numrow][num] = msg[2].i;
                    continue;

                } else if (!strncmp(msg[0].address + (len - offset - 3) - 3, "bm/", 3) && (num != -1)) {

                    if (isdigit(msg[0].address[len - 3])) 
                    {       
                        num = msg[0].address[len - 3] - '0' - 1;

                        if (isdigit(msg[0].address[len - 4])) 
                        {
                            num += 10;
                        }
                    }

                    if (isdigit(msg[0].address[len - 1])) 
                    {       
                        numrow = msg[0].address[len - 1] - '0' - 1;
                    }

                    gBeatsMatrix[numrow][num] = msg[2].i;
                    continue;

                } else if (!strncmp(msg[0].address + (len - offset) - 4, "bpc/", 4) && (num != -1)) {
                    if (num > 15) continue;
                    gPulseCountBeats[num] = msg[2].f;
                    continue;

                } else if (!strncmp(msg[0].address + (len - offset) - 4, "blv/", 4) && (num != -1)) {
                    if (num > 7) continue;
                    gBeatsLevel[num] = msg[2].f;
                    continue;

                } else if (!strncmp(msg[0].address + (len - offset) - 4, "bdc/", 4) && (num != -1)) {
                    if (num > 7) continue;
                    gBeatsDecay[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 if (MODE_RND || MODE_LFO) {
                    
                    if (!strncmp(msg[0].address + (len - offset) - 3, "acv", 3) && (num != -1)) {
                        if (num > 3) continue;                                             
                        gArdCV[num] = msg[2].i;
                        continue;

                    } else if (!strncmp(msg[0].address + (len - offset) - 3, "pot", 3) && (num != -1)) {
                        if (num > 1) continue;                                             
                        gArdPot[num] = msg[2].f;
                        continue;

                    } else if (!strncmp(msg[0].address + (len - offset) - 2, "sw", 2) && (num != -1)) {
                        if (num > 1) continue;
                        if (msg[2].i != 0) gArdSW[num] = true;
                        else               gArdSW[num] = false;                                       
                        continue;

                    }
                    
                } else {
                    
                    continue;
                }

            } while (bundleflag);
    }
}