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:
- 2013-01-28
- Revision:
- 6:5796b63c70ef
- Parent:
- 5:e305509d53f3
- Child:
- 7:a04f8378662e
File content as of revision 6:5796b63c70ef:
//------------------------------------------------------------- // 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_LIN 0 // Linear LinearCV Mode #define MODE_QChr 1 // Chromatic Quantize Mode #define MODE_QMaj 2 // Major #define MODE_QDor 3 // Dorian #define MODE_Q5th 4 // 5th #define MODE_QWht 5 // Wholetone #define MODE_SEQ 6 // Sequencer & Shift Register #define MODE_Calb 7 // Calibration (for VCO Tuning) #define MODE_NUM 8 // Modes #define QUAN_RES1 116 // Quantize voltage Steps #define QUAN_RES2 69 #define QUAN_RES3 68 #define QUAN_RES4 17 #define QUAN_RES5 58 #define SPI_RATE 40000000 // 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 UpdateCV(int, int, const unsigned int*); int UpdateGate(int, int, int, int, int); void SetCV(void); void SeqCV(int); void CheckModeSW(void); 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.00663080, 0.01433030, 0.02202980, 0.02972930, 0.03742880, 0.04512830, 0.05282781, 0.06052731, 0.06822681, 0.07592630, 0.08362581, 0.09132531, 0.09902481, 0.10672431, 0.11442380, 0.12212331, 0.12951356, 0.13671936, 0.14392516, 0.15113096, 0.15833676, 0.16554256, 0.17274836, 0.17995416, 0.18715996, 0.19436575, 0.20157155, 0.20877735, 0.21598317, 0.22318897, 0.23039477, 0.23760056, 0.24480636, 0.25202271, 0.25926629, 0.26650983, 0.27375340, 0.28099698, 0.28824055, 0.29548413, 0.30272770, 0.30997124, 0.31721482, 0.32445839, 0.33170196, 0.33894554, 0.34618911, 0.35343266, 0.36067623, 0.36791980, 0.37516347, 0.38241133, 0.38965923, 0.39690709, 0.40415496, 0.41140282, 0.41865072, 0.42589858, 0.43314645, 0.44039431, 0.44764221, 0.45489007, 0.46213794, 0.46938580, 0.47663370, 0.48388156, 0.49112943, 0.49837729, 0.50566339, 0.51296055, 0.52025765, 0.52755481, 0.53485191, 0.54214907, 0.54944617, 0.55674326, 0.56404042, 0.57133752, 0.57863468, 0.58593178, 0.59322894, 0.60052603, 0.60782319, 0.61512029, 0.62241745, 0.62976688, 0.63714498, 0.64452308, 0.65190119, 0.65927929, 0.66665739, 0.67403549, 0.68141359, 0.68879169, 0.69616979, 0.70354789, 0.71092600, 0.71830410, 0.72568226, 0.73306036, 0.74043846, 0.74781656, 0.75820577, 0.76986063, 0.78151548, 0.79317033, 0.80482519, 0.81648004, 0.82813489, 0.83978975, 0.85144460, 0.86309946, 0.87475431, 0.90686423, 0.93941462, 0.97196496 }; // Major Scale const float calibMap2[QUAN_RES2] = { 0.00663080, 0.01433030, 0.02972930, 0.04512830, 0.05282781, 0.06822681, 0.08362581, 0.09902481, 0.10672431, 0.12212331, 0.13671936, 0.14392516, 0.15833676, 0.17274836, 0.18715996, 0.19436575, 0.20877735, 0.22318897, 0.23039477, 0.24480636, 0.25926629, 0.27375340, 0.28099698, 0.29548413, 0.30997124, 0.31721482, 0.33170196, 0.34618911, 0.36067623, 0.36791980, 0.38241133, 0.39690709, 0.40415496, 0.41865072, 0.43314645, 0.44764221, 0.45489007, 0.46938580, 0.48388156, 0.49112943, 0.50566339, 0.52025765, 0.53485191, 0.54214907, 0.55674326, 0.57133752, 0.57863468, 0.59322894, 0.60782319, 0.62241745, 0.62976688, 0.64452308, 0.65927929, 0.66665739, 0.68141359, 0.69616979, 0.71092600, 0.71830410, 0.73306036, 0.74781656, 0.75820577, 0.78151548, 0.80482519, 0.82813489, 0.83978975, 0.86309946, 0.90686423, 0.93941462 }; // Dorian Scale const float calibMap3[QUAN_RES3] = { 0.00663080, 0.01433030, 0.02972930, 0.04512830, 0.06052731, 0.06822681, 0.08362581, 0.09902481, 0.10672431, 0.12212331, 0.13671936, 0.15113096, 0.15833676, 0.17274836, 0.18715996, 0.19436575, 0.20877735, 0.22318897, 0.23760056, 0.24480636, 0.25926629, 0.27375340, 0.28099698, 0.29548413, 0.30997124, 0.32445839, 0.33170196, 0.34618911, 0.36067623, 0.36791980, 0.38241133, 0.39690709, 0.41140282, 0.41865072, 0.43314645, 0.44764221, 0.45489007, 0.46938580, 0.48388156, 0.49837729, 0.50566339, 0.52025765, 0.53485191, 0.54214907, 0.55674326, 0.57133752, 0.58593178, 0.59322894, 0.60782319, 0.62241745, 0.62976688, 0.64452308, 0.65927929, 0.67403549, 0.68141359, 0.69616979, 0.71092600, 0.71830410, 0.73306036, 0.74781656, 0.76986063, 0.78151548, 0.80482519, 0.82813489, 0.83978975, 0.86309946, 0.90686423, 0.97196496 }; // 5th const float calibMap4[QUAN_RES4] = { 0.00663080, 0.06052731, 0.11442380, 0.16554256, 0.21598317, 0.26650983, 0.31721482, 0.36791980, 0.41865072, 0.46938580, 0.52025765, 0.57133752, 0.62241745, 0.67403549, 0.72568226, 0.79317033, 0.87475431 }; // Whole tone const float calibMap5[QUAN_RES5] = { 0.00663080, 0.02202980, 0.03742880, 0.05282781, 0.06822681, 0.08362581, 0.09902481, 0.11442380, 0.12951356, 0.14392516, 0.15833676, 0.17274836, 0.18715996, 0.20157155, 0.21598317, 0.23039477, 0.24480636, 0.25926629, 0.27375340, 0.28824055, 0.30272770, 0.31721482, 0.33170196, 0.34618911, 0.36067623, 0.37516347, 0.38965923, 0.40415496, 0.41865072, 0.43314645, 0.44764221, 0.46213794, 0.47663370, 0.49112943, 0.50566339, 0.52025765, 0.53485191, 0.54944617, 0.56404042, 0.57863468, 0.59322894, 0.60782319, 0.62241745, 0.63714498, 0.65190119, 0.66665739, 0.68141359, 0.69616979, 0.71092600, 0.72568226, 0.74043846, 0.75820577, 0.78151548, 0.80482519, 0.82813489, 0.85144460, 0.87475431, 0.93941462 }; //------------------------------------------------------------- // 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 static float gOSC_cv[8]; static float gSeq_cv1[8]; static float gSeq_cv2[8]; static float gGlide; volatile static int gMode; // Variables for Control float gCtrl[2]; volatile int gCtrlSW[4]; //------------------------------------------------------------- // 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] = {p22, p23, 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() { static float pot, _pot; int bpm, _bpm; int shift1, shift2, shift3, shift4; 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; bpm = _bpm = 120; 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: bpm = (gCtrl[0] * 300 + 10); // Set BPM (gCtrl[0]) if(abs(bpm - _bpm) > 1) { UpdateGate(bpm, NRESET, GATEALL, 3, 0); // Reset (if bpm change) _bpm = bpm; } else if (gCtrlSW[0] == 1) { // Stop (gCtrlSW[0]) bpm = 0; } if(gCtrlSW[2] == 0 && gCtrlSW[3] == 0) // Sequencer Mode1 { shift1 = UpdateGate(bpm, N16TH, GATE1, 3, 0); // Shift Timming 16th note UpdateGate(bpm, N8TH, GATE2, 3, 0); UpdateGate(bpm, NDOT8, GATE3, 3, 0); UpdateGate(bpm, TRIP4, GATE4, 3, 0); SeqCV(shift1); // Do shift ch all continue; } else if (gCtrlSW[2] == 1 && gCtrlSW[3] == 0) { // Sequencer Mode2 (if gCtrlSW[2] ON) shift1 = UpdateGate(bpm, N16TH, GATE1, 3, 0); shift2 = UpdateGate(bpm, N8TH, GATE2, 3, 0); shift3 = UpdateGate(bpm, NDOT4, GATE3, 3, 0); shift4 = UpdateGate(bpm, TRIP8, GATE4, 3, 0); SeqCV(shift1); // Do shift ch 1~5 SeqCV(shift2); // Do shift ch 6 SeqCV(shift3); // Do shift ch 7 SeqCV(shift4); // Do shift ch 8 continue; } else if (gCtrlSW[3] == 1) { // Sequencer Mode3 (if gCtrlSW[3] ON) // (ch6,7,8, short loop) shift1 = UpdateGate(bpm, N16TH, GATE1, 3, 0); shift2 = UpdateGate(bpm, N8TH, GATE2, 3, 0); shift3 = UpdateGate(bpm, NDOT8, GATE3, 3, 0); shift4 = UpdateGate(bpm, TRIP4, GATE4, 3, 0); SeqCV(shift1); // Do shift ch 1~5 SeqCV(shift2); // Do shift ch 6 SeqCV(shift3); // Do shift ch 7 SeqCV(shift4); // Do shift ch 8 continue; } default: SetCV(); continue; } } } //------------------------------------------------------------- // 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(); } //------------------------------------------------------------- // GateOutSequence beat(Note values) length(Gate time) invert(invert Gate) int UpdateGate(int bpm, int beat, int ch, int length, int invert) { static int gatetime[4]; static int oldgatetime[4]; static int bar; static int sync24; static int 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(int 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 == 0) { oldgatetime[ch] = time; gLEDS[ch] = gGATES[ch] = 1; return ch + 1; } else if (time > oldgatetime[ch] + gatetime[ch] && invert == 1) { oldgatetime[ch] = time; gLEDS[ch] = gGATES[ch] = 0; return 0; } else if (time > oldgatetime[ch] + (gatetime[ch] - gatetime[ch] / length) && invert == 0) { gLEDS[ch] = gGATES[ch] = 0; return 0; } else if (time > oldgatetime[ch] + (gatetime[ch] - gatetime[ch] / length) && invert == 1) { gLEDS[ch] = gGATES[ch] = 1; return ch + 1; } else { return -1; } } //------------------------------------------------------------- // Calculate CV void SetCV() { static int ch; float glidecv[8]; unsigned int cv[8]; static float oldcv[8]; static unsigned int quan; float qcv; switch(gMode) { case MODE_LIN: glidecv[ch] = oldcv[ch] * gGlide + gOSC_cv[ch] * (1.0f - gGlide); oldcv[ch] = glidecv[ch]; 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)]; glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); oldcv[ch] = glidecv[ch]; 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)]; glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); oldcv[ch] = glidecv[ch]; cv[ch] = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]); break; case MODE_QDor: quan = 40616 / QUAN_RES3; qcv = calibMap3[(unsigned int)(gOSC_cv[ch] / quan)]; glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); oldcv[ch] = glidecv[ch]; cv[ch] = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]); break; case MODE_Q5th: quan = 40616 / QUAN_RES4; qcv = calibMap4[(unsigned int)(gOSC_cv[ch] / quan)]; glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); oldcv[ch] = glidecv[ch]; cv[ch] = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]); break; case MODE_QWht: quan = 40616 / QUAN_RES5; qcv = calibMap5[(unsigned int)(gOSC_cv[ch] / quan)]; glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); oldcv[ch] = glidecv[ch]; cv[ch] = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]); break; case MODE_Calb: cv[ch] = 19212; // A440.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; } //------------------------------------------------------------- // Sequence & Shift Out CV void SeqCV(int shift) { int i, j, k; static int ch; static int cnt1, cnt2, cnt3; static int cntloop1, cntloop2, cntloop3; static int SeqMode; static float glidecv[8]; unsigned int cv[8]; static float shiftcv[8]; static float buffercv[9]; static float loopcv[3]; static unsigned int quan; float qcv; SeqMode = (unsigned int)(gCtrl[1] * (MODE_NUM - 3)); // Sequencer Quantize Mode (gCtrl[1]) switch(SeqMode) { case MODE_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 MODE_QChr: 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 MODE_QMaj: 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 MODE_QDor: 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 MODE_Q5th: 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 MODE_QWht: 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; } if((gCtrlSW[2] == 0 || gCtrlSW[2] == 1) && gCtrlSW[3] == 0)// 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(i = 1; i < 8; ++i) // Shift ch2~8 { shiftcv[i] = glidecv[i-1]; } ch++; ch &= 0x0F; } cnt1 = cnt2 = cnt3 = 0; } } else if (gCtrlSW[2] == 1 && gCtrlSW[3] == 0) { // Sequencer Mode2 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 } } else if (gCtrlSW[3] == 1) { // Sequencer Mode3 for(j = 1; j < 5; ++j) { glidecv[j] = glidecv[j] * gGlide + shiftcv[j] * (1.0f - gGlide); cv[j] = (unsigned int)glidecv[j]; UpdateCV(WRITE_UPDATE_N, j, &cv[j]); } for(k = 5; k < 8; ++k) { glidecv[k] = glidecv[k] * gGlide + loopcv[k - 5] * (1.0f - gGlide); cv[k] = (unsigned int)glidecv[k]; UpdateCV(WRITE_UPDATE_N, k, &cv[k]); } if(shift == 1) // GATE1 { for(i = 1; i < 8; ++i) { shiftcv[i] = glidecv[i-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] == 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]); } } //------------------------------------------------------------- // Check SW void CheckModeSW() { wait(0.02); 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(); } //------------------------------------------------------------- // CV meter void CVMeter(int ch, const unsigned int *level) { static unsigned int cvmeter; cvmeter = *level / (SCALING_N / 7.9); gLCD.locate ( ch, 0 ); gLCD.putc(cvmeter); // put custom char } //------------------------------------------------------------- // Print LCD Mode Status void LCD() { switch(gMode) { 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_Calb: gLCD.locate( 9, 0 ); gLCD.printf("Calibr "); 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]; static int num; unsigned int absv; switch(e) { case UDPSOCKET_READABLE: // The only event for now char buf[256] = {0}; Host host; while( int len = gUdp.recvfrom( buf, 256, &host )) { if(len <= 0) break; // printf("\r\nFrom %d.%d.%d.%d:\r\n", // host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3]); getOSCmsg(buf,msg); // printf("OSCmsg: %s %s %f %i\r\n", // msg[0].address, msg[1].typeTag, msg[2].f, msg[2].i); 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)==0) { if(absv >= 1 || msg[2].i >= 1) gCLOCKOUT = 1; else gCLOCKOUT = 0; break; } else if ((strncmp(msg[0].address+(len-1)-4, "gate", 4)==0) && (num != -1)) { if(num > 3) break; if(absv >= 1 || msg[2].i >= 1) gLEDS[num] = gGATES[num] = 1; else gLEDS[num] = gGATES[num] = 0; break; // (touchOSC Control push, toggle) } else if ((strncmp(msg[0].address+(len-1)-4, "push", 4)==0) && (num != -1)) { if(num > 3) break; if(absv >= 1 || msg[2].i >= 1) gLEDS[num] = gGATES[num] = 1; else gLEDS[num] = gGATES[num] = 0; break; } else if ((strncmp(msg[0].address+(len-1)-6, "toggle", 6)==0) && (num != -1)) { if(num > 3) break; if(absv >= 1 || msg[2].i >= 1) gLEDS[num] = gGATES[num] = 1; else gLEDS[num] = gGATES[num] = 0; break; } else if ((strncmp(msg[0].address,"/1/multipush",12)==0) && (num != -1)) { if(num > 3) break; if(absv >= 1 || msg[2].i >= 1) gLEDS[num] = gGATES[num] = 1; else gLEDS[num] = gGATES[num] = 0; break; } // address pattern CV (Type Tag float) if((strncmp(msg[0].address+(len-1)-2, "cv", 2)==0) && (num != -1)) { if(num > 7) break; if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); break; // (touchOSC Control fader, rotary, xy, multixy, multifader) } else if ((strncmp(msg[0].address+(len-1)-5, "fader", 5)==0) && (num != -1)) { if(num > 7) break; if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); break; } else if ((strncmp(msg[0].address+(len-1)-6, "rotary", 6)==0) && (num != -1)) { if(num > 7) break; if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); break; } else if ((strncmp(msg[0].address+(len-1)-2, "xy", 2)==0) && (num != -1)) { if(num > 7) break; 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); break; } else if ((strncmp(msg[0].address+(len-1)-9, "multixy1/", 9)==0) && (num != -1)) { if(num > 7) break; 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); break; } else if ((strncmp(msg[0].address+(len-1)-12, "multifader1/", 12)==0) && (num != -1)) { if(num > 7) break; if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); break; // (touchOSC multifader for Sequencer Mode) } else if ((strncmp(msg[0].address+(len-1)-11, "sequencer1/", 11)==0) && (num != -1)) { if(num > 7) break; if(msg[1].typeTag[1] == 'f') gSeq_cv1[num] = msg[2].f * (SCALING_N); break; } else if ((strncmp(msg[0].address+(len-1)-11, "sequencer2/", 11)==0) && (num != -1)) { if(num > 7) break; if(msg[1].typeTag[1] == 'f') gSeq_cv2[num] = msg[2].f * (SCALING_N); break; } // address pattern for control if ((strncmp(msg[0].address+(len-1)-6, "ctrlsw", 6)==0) && (num != -1)) { if(num > 4) break; if(absv >= 1 || msg[2].i >= 1) gCtrlSW[num] = 1; else gCtrlSW[num] = 0; break; } else if ((strncmp(msg[0].address+(len-1)-4, "ctrl", 4)==0) && (num != -1)) { if(num > 2) break; if(msg[1].typeTag[1] == 'f') gCtrl[num] = msg[2].f; break; } } } }