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
main.cpp
- Committer:
- casiotone401
- Date:
- 2016-01-17
- Revision:
- 23:2cb7fad36ce0
- Parent:
- 21:2273c3676f1b
- Child:
- 24:99045b0f7c4a
File content as of revision 23:2cb7fad36ce0:
//------------------------------------------------------------- // 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 "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_Calb 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_EUC 4 // Mode Euclidean Sequencer #define MODE_RND 5 // Mode xshift Random Generator #define MODE_LFO 6 // Mode Stepped LFO #define MODE_TOTAL 7 // Modes //------------------------------------------------------------- // Functions void InitOSCCV(void); inline void NetPoll(void); void CalibrationCV(void); inline void SetCV(void); inline int CheckBPM(void); void CheckModeSW(void); inline void LCD(); 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 pot, _pot; int bpm; InitOSCCV(); InitEuclideanSeq(); // Init Euclidean Sequencer 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); } bpm = CheckBPM(); // check current BPM switch (gMode) { case MODE_OSC: // OSCtoCV mode SetCV(); break; case MODE_SEQ: // Shift Sequencer mode 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 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 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; case MODE_RND: // Random CV Generator mode RandomCVGenerator(GateSeq(bpm, N32TH, GATE1, 3, NON_INVERT, GATESOUT_OFF, SYNC_ON)); break; case MODE_LFO: // Stepped LFO mode SteppedLFO(); break; default: // CV Calibration mode CalibrationCV(); break; } } } //------------------------------------------------------------- // Ethernet Polling inline void NetPoll() { Net::poll(); } //------------------------------------------------------------- // Initialize OSCtoCV void InitOSCCV() { int i; //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 = 0x00020038; /* 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(); //----------------------------------------------------------------------------- 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 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; // Set OSC message for sending sendMes.setIp(touchOSCAddress); sendMes.setPort(touchOSCPort); gSW.attach(&CheckModeSW,IRQ_RISE, 30); // InterruptIn rising edge(ModeSW) wait(0.5); gPoller.attach_us(&NetPoll, POLLING_INTERVAL); // Ticker Polling wait(1.8); } //------------------------------------------------------------- // Calibration Mode void CalibrationCV() { static int ch; unsigned int cv; switch (gMode) { case MODE_Calb: 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); break; } UpdateCVMeter(ch, &cv); ++ch; ch &= 0x07; } //------------------------------------------------------------- // Calculate CV inline void SetCV() { static int ch, qmode, amode, mcount; static float glidecv[8]; unsigned int cv; static float qcv; qmode = (gCtrl[1] * (SCALE_NUM - 1)); amode = SCALE_AOUT * qmode; gAOUT.write_u16(amode); switch (qmode) { 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 (abs(bpm - _bpm) > 1) { _bpm = bpm; sendMes.setTopAddress("/bpm"); sendMes.setArgs("i", bpm); osc.sendOsc(&sendMes); } } return bpm; } //------------------------------------------------------------- // 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_SEQ || gMode == MODE_185 || gMode == MODE_EUC || gMode == MODE_RND || gMode == MODE_LFO) { gTimer.start(); // Sequencer Timer Start midi.begin(1); } else { gTimer.stop(); // Sequencer Timer Stop } } //------------------------------------------------------------- // 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"); 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_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) { 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[896] = {0}; static int recvlen; static int num, len, offset; int messagepos = 0; bool bundleflag = false; Host host; switch (e) { case UDPSOCKET_READABLE: // The only event for now recvlen = gUdp.recvfrom(buf, 896, &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 <= 8) { 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; } // address pattern SYNC & GATE (Type Tag int, float) 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) -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) - 6, "slide/", 6) && (num != -1)) { if (num > 15) continue; gSlide[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) - 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 (!strncmp(msg[0].address + (len - offset) - 3, "acv", 3) && (num != -1)) { if (num > 3) continue; gArdCV[num] = msg[2].f * (SCALING_N); 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); } }