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:
- 2014-10-16
- Revision:
- 14:977f3c5a4b4e
- Parent:
- 13:3f42e451a8d3
- Child:
- 15:3e4bc47d6a39
File content as of revision 14:977f3c5a4b4e:
//------------------------------------------------------------- // 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_SEQ 2 // Mode Shift #define MODE_NUM 3 // 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 20000000 // 20Mbps 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 UpdateCV(int, int, const unsigned int*); inline void CalibCV(void); inline void SetSCV(void); inline void SeqCV(int); inline void Seq(void); inline int UpdateGate(int, int, int, int, bool); inline void UpdateSync(int, int, bool); void CheckModeSW(void); inline void CVMeter(int, const unsigned int*); void LCD(); void WriteCustomChar(unsigned char, unsigned char*); int SetupEthNetIf(void); inline size_t strlength(const char *); inline void onUDPSocketEvent(UDPSocketEvent); //------------------------------------------------------------- // Silentway Calibration Data Mapping // http://www.expert-sleepers.co.uk/silentway.html // Chromatic Scale const float calibMap1[QUAN_RES1] = { 0.00331362, 0.01097947, 0.01864531, 0.02631116, 0.03397701, 0.04164285, 0.04930869, 0.05697454, 0.06464039, 0.07230624, 0.07997208, 0.08763793, 0.09530377, 0.10296962, 0.11063547, 0.11830132, 0.12590303, 0.13306051, 0.14021800, 0.14737549, 0.15453300, 0.16169049, 0.16884798, 0.17600547, 0.18316296, 0.19032045, 0.19747795, 0.20463544, 0.21179293, 0.21895042, 0.22610791, 0.23326540, 0.24042290, 0.24758039, 0.25476459, 0.26196238, 0.26916021, 0.27635801, 0.28355584, 0.29075363, 0.29795146, 0.30514926, 0.31234708, 0.31954488, 0.32674271, 0.33394051, 0.34113833, 0.34833613, 0.35553396, 0.36273175, 0.36992958, 0.37713069, 0.38433966, 0.39154866, 0.39875764, 0.40596664, 0.41317561, 0.42038459, 0.42759359, 0.43480256, 0.44201156, 0.44922054, 0.45642951, 0.46363851, 0.47084749, 0.47805649, 0.48526546, 0.49247447, 0.49968344, 0.50694764, 0.51421440, 0.52148110, 0.52874786, 0.53601462, 0.54328132, 0.55054808, 0.55781484, 0.56508154, 0.57234830, 0.57961506, 0.58688176, 0.59414852, 0.60141528, 0.60868198, 0.61594874, 0.62321550, 0.63052768, 0.63785475, 0.64518178, 0.65250880, 0.65983582, 0.66716284, 0.67448992, 0.68181694, 0.68914396, 0.69647098, 0.70379800, 0.71112502, 0.71845210, 0.72577912, 0.73310614, 0.74043316, 0.74776018, 0.75861782, 0.77102989, 0.78344196, 0.79585397, 0.80826604, 0.82067811, 0.83309019, 0.84550226, 0.85791427, 0.87032634, 0.90296346, 0.94781560 }; // Major Scale const float calibMap2[QUAN_RES2] = { 0.01097947, 0.02631116, 0.03397701, 0.04930869, 0.06464039, 0.07997208, 0.08763793, 0.10296962, 0.11830132, 0.12590303, 0.14021800, 0.15453300, 0.16884798, 0.17600547, 0.19032045, 0.20463544, 0.21179293, 0.22610791, 0.24042290, 0.25476459, 0.26196238, 0.27635801, 0.29075363, 0.29795146, 0.31234708, 0.32674271, 0.34113833, 0.34833613, 0.36273175, 0.37713069, 0.38433966, 0.39875764, 0.41317561, 0.42759359, 0.43480256, 0.44922054, 0.46363851, 0.47084749, 0.48526546, 0.49968344, 0.51421440, 0.52148110, 0.53601462, 0.55054808, 0.55781484, 0.57234830, 0.58688176, 0.60141528, 0.60868198, 0.62321550, 0.63785475, 0.64518178, 0.65983582, 0.67448992, 0.68914396, 0.69647098, 0.71112502, 0.72577912, 0.73310614, 0.74776018, 0.77102989, 0.79585397, 0.80826604, 0.83309019, 0.85791427, 0.87032634, 0.94781560 }; // M7(9) const float calibMap3[QUAN_RES3] = { 0.02631116, 0.04930869, 0.07997208, 0.08763793, 0.11830132, 0.14021800, 0.16884798, 0.17600547, 0.20463544, 0.22610791, 0.25476459, 0.26196238, 0.29075363, 0.31234708, 0.34113833, 0.34833613, 0.37713069, 0.39875764, 0.42759359, 0.43480256, 0.44922054, 0.46363851, 0.48526546, 0.51421440, 0.52148110, 0.55054808, 0.57234830, 0.60141528, 0.60868198, 0.62321550, 0.63785475, 0.65983582, 0.68914396, 0.69647098, 0.72577912, 0.74776018, 0.79585397, 0.85791427, 0.94781560 }; // m7(9) const float calibMap4[QUAN_RES4] = { 0.01097947, 0.01864531, 0.03397701, 0.04930869, 0.07230624, 0.08763793, 0.11063547, 0.14021800, 0.16169049, 0.17600547, 0.19747795, 0.22610791, 0.24042290, 0.24758039, 0.26196238, 0.29075363, 0.31234708, 0.33394051, 0.34833613, 0.36273175, 0.36992958, 0.38433966, 0.39875764, 0.41317561, 0.42038459, 0.43480256, 0.45642951, 0.48526546, 0.50694764, 0.52148110, 0.53601462, 0.55781484, 0.57234830, 0.59414852, 0.62321550, 0.63052768, 0.64518178, 0.65983582, 0.68181694, 0.69647098, 0.71845210, 0.74776018, 0.77102989, 0.78344196, 0.80826604, 0.83309019, 0.84550226, 0.94781560 }; // Dorian Scale const float calibMap5[QUAN_RES5] = { 0.01097947, 0.02631116, 0.04164285, 0.04930869, 0.06464039, 0.07997208, 0.08763793, 0.10296962, 0.11830132, 0.13306051, 0.14021800, 0.15453300, 0.16884798, 0.17600547, 0.19032045, 0.20463544, 0.21895042, 0.22610791, 0.24042290, 0.25476459, 0.26196238, 0.27635801, 0.29075363, 0.30514926, 0.31234708, 0.32674271, 0.34113833, 0.34833613, 0.36273175, 0.37713069, 0.39154866, 0.39875764, 0.41317561, 0.42759359, 0.43480256, 0.44922054, 0.46363851, 0.47805649, 0.48526546, 0.49968344, 0.51421440, 0.52148110, 0.53601462, 0.55054808, 0.56508154, 0.57234830, 0.58688176, 0.60141528, 0.60868198, 0.62321550, 0.63785475, 0.65250880, 0.65983582, 0.67448992, 0.68914396, 0.69647098, 0.71112502, 0.72577912, 0.74043316, 0.74776018, 0.77102989, 0.79585397, 0.80826604, 0.83309019, 0.85791427, 0.90296346, 0.94781560 }; // Minor Scale const float calibMap6[QUAN_RES6] = { 0.01097947, 0.01864531, 0.03397701, 0.04930869, 0.05697454, 0.07230624, 0.08763793, 0.10296962, 0.11063547, 0.12590303, 0.14021800, 0.14737549, 0.16169049, 0.17600547, 0.19032045, 0.19747795, 0.21179293, 0.22610791, 0.23326540, 0.24758039, 0.26196238, 0.27635801, 0.28355584, 0.29795146, 0.31234708, 0.31954488, 0.33394051, 0.34833613, 0.36273175, 0.36992958, 0.38433966, 0.39875764, 0.40596664, 0.42038459, 0.43480256, 0.44922054, 0.45642951, 0.47084749, 0.48526546, 0.49247447, 0.50694764, 0.52148110, 0.53601462, 0.54328132, 0.55781484, 0.57234830, 0.57961506, 0.59414852, 0.60868198, 0.62321550, 0.63052768, 0.64518178, 0.65983582, 0.66716284, 0.68181694, 0.69647098, 0.71112502, 0.71845210, 0.73310614, 0.74776018, 0.75861782, 0.78344196, 0.80826604, 0.83309019, 0.84550226, 0.87032634, 0.94781560 }; // 5th const float calibMap7[QUAN_RES7] = { 0.01097947, 0.06464039, 0.11830132, 0.16884798, 0.21895042, 0.26916021, 0.31954488, 0.36992958, 0.42038459, 0.47084749, 0.52148110, 0.57234830, 0.62321550, 0.67448992, 0.72577912, 0.79585397, 0.90296346 }; // Whole tone const float calibMap8[QUAN_RES8] = { 0.01097947, 0.02631116, 0.04164285, 0.05697454, 0.07230624, 0.08763793, 0.10296962, 0.11830132, 0.13306051, 0.14737549, 0.16169049, 0.17600547, 0.19032045, 0.20463544, 0.21895042, 0.23326540, 0.24758039, 0.26196238, 0.27635801, 0.29075363, 0.30514926, 0.31954488, 0.33394051, 0.34833613, 0.36273175, 0.37713069, 0.39154866, 0.40596664, 0.42038459, 0.43480256, 0.44922054, 0.46363851, 0.47805649, 0.49247447, 0.50694764, 0.52148110, 0.53601462, 0.55054808, 0.56508154, 0.57961506, 0.59414852, 0.60868198, 0.62321550, 0.63785475, 0.65250880, 0.66716284, 0.68181694, 0.69647098, 0.71112502, 0.72577912, 0.74043316, 0.75861782, 0.78344196, 0.80826604, 0.83309019, 0.85791427, 0.90296346 }; //------------------------------------------------------------- // 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; int gMode; // Variables for Control float gCtrl[6]; bool gCtrlSW[6] = {false}; //------------------------------------------------------------- // mbed Functions TextLCD gLCD(p9, p10, p11, p12, p13, p14); // rs, e, d4-d7 SPI gSPI(p5,p6,p7); // SPI (p6 unconnected) DigitalOut gSYNCMODE(p15); // SYNC DAC8568 DigitalOut gLDAC(p16); // LDAC DAC8568 DigitalOut gGATES[4] = {p23, p24, p24, p25}; // GateOut DigitalOut gLEDS[4] = {p18, p19, p20, p21}; // LED DigitalOut gCLOCKOUT(p26); // ClockOut AnalogIn gAIN(p17); // Glide Potentiometer InterruptIn gSW(p30); // Mode SW Timer gTimer; // Timer Ticker gPoller; // Ticker Polling // Ethernet EthernetNetIf gEth; UDPSocket gUdp; //------------------------------------------------------------- // main int main() { float pot, _pot; //Clock Up 110Mhz ------------------------------------------------------------- LPC_SC->PLL0CON = 0x00; /* PLL0 Disable */ LPC_SC->PLL0FEED = 0xAA; LPC_SC->PLL0FEED = 0x55; LPC_SC->CCLKCFG = 0x00000003; /* Select Clock Divisor = 4 */ LPC_SC->PLL0CFG = 0x00020037; /* configure PLL0 */ LPC_SC->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 = gMode = 0; gGlide = gCtrl[3] = gAIN.read(); LCD(); gLCD.locate( 0, 1 ); gLCD.printf("12345678 G>>%3.2f", gGlide); // loop while(1) { pot = gAIN.read(); // Glide Value if(pot == 0) { if(abs(gCtrl[3] - _pot) > 0.01f) { _pot = gGlide = gCtrl[3]; gLCD.locate( 0, 1 ); gLCD.printf("12345678 G>>%3.2f", gGlide); } } else if (abs(pot - _pot) > 0.01f) { gGlide = _pot = gAIN.read(); gLCD.locate( 0, 1 ); gLCD.printf("12345678 G>>%3.2f", gGlide); } switch(gMode) { case MODE_LIN: SetSCV(); break; case MODE_SEQ: Seq(); break; default: CalibCV(); break; } } } //------------------------------------------------------------- // Ethernet Polling inline void NetPoll() { Net::poll(); } //------------------------------------------------------------- // 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); } //------------------------------------------------------------- // SPI Transfer // DAC8568 data word length 32bit (8bit shift out) inline void UpdateCV(int control, int address, const unsigned int *data) { __disable_irq(); 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; } __enable_irq(); } //------------------------------------------------------------- // Calibrate Mode inline void CalibCV() { static int ch; unsigned int cv; switch(gMode) { case MODE_Calb: cv = (unsigned int)((calibMap1[68] + 0.0007) * SCALING_N); // 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); break; } CVMeter(ch, &cv); ch++; ch &= 0x07; } //------------------------------------------------------------- // Calculate CV inline void SetSCV() { static int ch, quan, mode, mcount; static float glidecv[8]; unsigned int cv; static float qcv; mode = (gCtrl[1] * 8); switch(mode) { case Lin: glidecv[ch] = glidecv[ch] * gGlide + gOSC_cv[ch] * (1.0f - gGlide); cv = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv); break; case Chr: quan = (40616 / QUAN_RES1); qcv = calibMap1[(unsigned int)(gOSC_cv[ch] / quan)]; glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv); break; case Maj: quan = (40616 / QUAN_RES2); qcv = calibMap2[(unsigned int)(gOSC_cv[ch] / quan)]; glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv); break; case M7: quan = (40616 / QUAN_RES3); qcv = calibMap3[(unsigned int)(gOSC_cv[ch] / quan)]; glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv); break; case Min7: quan = (40616 / QUAN_RES4); qcv = calibMap4[(unsigned int)(gOSC_cv[ch] / quan)]; glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv); break; case Dor: quan = (40616 / QUAN_RES5); qcv = calibMap5[(unsigned int)(gOSC_cv[ch] / quan)]; glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv); break; case Min: quan = (40616 / QUAN_RES6); qcv = calibMap6[(unsigned int)(gOSC_cv[ch] / quan)]; glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv); break; case S5th: quan = (40616 / QUAN_RES7); qcv = calibMap7[(unsigned int)(gOSC_cv[ch] / quan)]; glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv); break; case Wht: quan = (40616 / QUAN_RES8); qcv = calibMap8[(unsigned int)(gOSC_cv[ch] / quan)]; glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv); break; } if(mcount % 16 == 0) { CVMeter(ch, &cv); } ch++; if(ch &= 0x07) { mcount ++; mcount &= 0x3F; } } //------------------------------------------------------------- // Sequence & Shift Out CV inline void SeqCV(int shift) { int i, j; static int ch, quan, mode; static float glidecv[8], shiftcv[8]; unsigned int cv; static 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 = (unsigned int)glidecv[0]; UpdateCV(WRITE_UPDATE_N, 0, &cv); 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 = (unsigned int)glidecv[0]; UpdateCV(WRITE_UPDATE_N, 0, &cv); break; case Maj: quan = 40616 / QUAN_RES2; if(ch < 8) { qcv = calibMap2[(unsigned int)(gSeq_cv1[ch] / quan)]; } else { qcv = calibMap2[(unsigned int)(gSeq_cv2[ch-8] / quan)]; } glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[0]; UpdateCV(WRITE_UPDATE_N, 0, &cv); break; case M7: quan = 40616 / QUAN_RES3; if(ch < 8) { qcv = calibMap3[(unsigned int)(gSeq_cv1[ch] / quan)]; } else { qcv = calibMap3[(unsigned int)(gSeq_cv2[ch-8] / quan)]; } glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[0]; UpdateCV(WRITE_UPDATE_N, 0, &cv); break; case Min7: quan = 40616 / QUAN_RES4; if(ch < 8) { qcv = calibMap4[(unsigned int)(gSeq_cv1[ch] / quan)]; } else { qcv = calibMap4[(unsigned int)(gSeq_cv2[ch-8] / quan)]; } glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[0]; UpdateCV(WRITE_UPDATE_N, 0, &cv); break; case Dor: quan = 40616 / QUAN_RES5; if(ch < 8) { qcv = calibMap5[(unsigned int)(gSeq_cv1[ch] / quan)]; } else { qcv = calibMap5[(unsigned int)(gSeq_cv2[ch-8] / quan)]; } glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[0]; UpdateCV(WRITE_UPDATE_N, 0, &cv); break; case Min: quan = 40616 / QUAN_RES6; if(ch < 8) { qcv = calibMap6[(unsigned int)(gSeq_cv1[ch] / quan)]; } else { qcv = calibMap6[(unsigned int)(gSeq_cv2[ch-8] / quan)]; } glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[0]; UpdateCV(WRITE_UPDATE_N, 0, &cv); break; case S5th: quan = 40616 / QUAN_RES7; if(ch < 8) { qcv = calibMap7[(unsigned int)(gSeq_cv1[ch] / quan)]; } else { qcv = calibMap7[(unsigned int)(gSeq_cv2[ch-8] / quan)]; } glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[0]; UpdateCV(WRITE_UPDATE_N, 0, &cv); break; case Wht: quan = 40616 / QUAN_RES8; if(ch < 8) { qcv = calibMap8[(unsigned int)(gSeq_cv1[ch] / quan)]; } else { qcv = calibMap8[(unsigned int)(gSeq_cv2[ch-8] / quan)]; } glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[0]; UpdateCV(WRITE_UPDATE_N, 0, &cv); break; } for(i = 1; i < 8; ++i) { glidecv[i] = glidecv[i] * gGlide + shiftcv[i] * (1.0f - gGlide); cv = (unsigned int)glidecv[i]; UpdateCV(WRITE_UPDATE_N, i, &cv); } if(shift == 1) // GATE1 { for(j = 1; j < 8; ++j) // Shift ch2~8 { shiftcv[j] = glidecv[j-1]; } ch++; ch &= 0x0F; } if(ch < 8) { CVMeter(ch, &cv); } else { CVMeter((ch-8), &cv); } } //------------------------------------------------------------- // 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); } } //------------------------------------------------------------- // 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) { gTimer.start(); // Sequencer Timer Start } else { gTimer.stop(); // Sequencer Timer Stop } LCD(); } //------------------------------------------------------------- // 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 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; } } //------------------------------------------------------------- // SyncOut Sequence beat(Note values) invert(invert Gate) inline void UpdateSync(int bpm, int beat, bool invert) { static int bar, synctime, oldsynctime; int time = gTimer.read_us(); bar = (60.0f / bpm) * 4000000; synctime = bar / beat; if(beat == NRESET) { bar = synctime = oldsynctime = gCLOCKOUT = 0; } if((time > oldsynctime + synctime) && !invert) { oldsynctime = time; gCLOCKOUT = 1; } else if ((time > synctime - (synctime / 2)) && !invert) { gCLOCKOUT = 0; } else if((time > oldsynctime + synctime) && invert) { oldsynctime = time; gCLOCKOUT = 0; } else if ((time > synctime - (synctime / 2)) && invert) { gCLOCKOUT = 1; } } //------------------------------------------------------------- // CV meter inline void CVMeter(int ch, const unsigned int *level) { gLCD.locate ( ch, 0 ); gLCD.putc(*level * 0.000205729); // put custom char } //------------------------------------------------------------- // Print LCD Mode Status void LCD() { switch(gMode) { case MODE_Calb: gLCD.locate( 9, 0 ); gLCD.printf("Calibr "); break; case MODE_LIN: gLCD.locate( 9, 0 ); gLCD.printf("OSC-CV "); break; case MODE_SEQ: gLCD.locate( 9, 0 ); gLCD.printf("SHIFTCV"); break; } } //------------------------------------------------------------- // 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; } //------------------------------------------------------------- // Fast strlen function http://www.strchr.com/optimized_strlen_function size_t strlength(const char *s) { size_t len = 0; for(;;) { unsigned x = *(unsigned*)s; if((x & 0xFF) == 0) return len; if((x & 0xFF00) == 0) return len + 1; if((x & 0xFF0000) == 0) return len + 2; if((x & 0xFF000000) == 0) return len + 3; s += 4, len += 4; } } //------------------------------------------------------------- // Handller receive UDP Packet inline void onUDPSocketEvent(UDPSocketEvent e) { union OSCarg msg[10]; char buf[768] = {0}; int num, len; int recvlen; int messagepos = 0; bool bundleflag = false; Host host; recvlen = gUdp.recvfrom(buf, 768, &host); // packet length switch(e) { case UDPSOCKET_READABLE: // The only event for now 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; } // address pattern SYNC & GATE (Type Tag int, float) if(!strncmp(msg[0].address+(len-1)-4, "sync", 4)) { if(msg[2].i != 0) gCLOCKOUT = 1; else gCLOCKOUT = 0; continue; } else if (!strncmp(msg[0].address+(len-1)-4, "gate", 4) && (num != -1)) { if(num > 3) continue; if(msg[2].i != 0) gLEDS[num] = gGATES[num] = 1; else gLEDS[num] = gGATES[num] = 0; continue; // (touchOSC Control push, toggle) } else if (!strncmp(msg[0].address+(len-1)-4, "push", 4) && (num != -1)) { if(num > 4) continue; if(msg[2].i != 0) gLEDS[num] = gGATES[num] = 1; else gLEDS[num] = gGATES[num] = 0; continue; } else if (!strncmp(msg[0].address+(len-1)-6, "toggle", 6) && (num != -1)) { if(num > 4) continue; if(msg[2].i != 0) gLEDS[num] = gGATES[num] = 1; else gLEDS[num] = gGATES[num] = 0; continue; } else if (!strncmp(msg[0].address,"/1/multipush",12) && (num != -1)) { if(num > 4) continue; if(msg[2].i != 0) gLEDS[num] = gGATES[num] = 1; else gLEDS[num] = gGATES[num] = 0; continue; // address pattern CV (Type Tag float) } else if(!strncmp(msg[0].address+(len-1)-2, "cv", 2) && (num != -1)) { if(num > 7) continue; if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); 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 > 5) continue; if(msg[2].i != 0) gCtrlSW[num] = true; else gCtrlSW[num] = false; continue; } else if (!strncmp(msg[0].address+(len-1)-4, "ctrl", 4) && (num != -1)) { if(num > 5) continue; if(msg[1].typeTag[1] == 'f') gCtrl[num] = msg[2].f; continue; } } while(bundleflag); } }