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-03-02
- Revision:
- 9:1ac3d135d965
- Parent:
- 8:fe50078d6b80
- Child:
- 10:ccfeb687c3f2
File content as of revision 9:1ac3d135d965:
//------------------------------------------------------------- // 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 115 // Quantize voltage Steps #define QUAN_RES2 67 #define QUAN_RES3 67 #define QUAN_RES4 17 #define QUAN_RES5 57 #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); inline void CVMeter(int, const unsigned int*); void LCD(); void WriteCustomChar(unsigned char, unsigned char*); int SetupEthNetIf(void); inline void onUDPSocketEvent(UDPSocketEvent); //------------------------------------------------------------- // Silentway Calibration Data Mapping // http://www.expert-sleepers.co.uk/silentway.html // Chromatic Scale const float calibMap1[QUAN_RES1] = { 0.00559238, 0.01324014, 0.02088790, 0.02853566, 0.03618342, 0.04383118, 0.05147894, 0.05912671, 0.06677447, 0.07442223, 0.08206999, 0.08971775, 0.09736551, 0.10501327, 0.11266103, 0.12030879, 0.12775089, 0.13486665, 0.14198242, 0.14909819, 0.15621395, 0.16332972, 0.17044549, 0.17756125, 0.18467702, 0.19179279, 0.19890857, 0.20602433, 0.21314010, 0.22025587, 0.22737163, 0.23448740, 0.24160317, 0.24871893, 0.25587305, 0.26303557, 0.27019811, 0.27736065, 0.28452319, 0.29168573, 0.29884824, 0.30601078, 0.31317332, 0.32033587, 0.32749838, 0.33466092, 0.34182346, 0.34898600, 0.35614854, 0.36331105, 0.37047359, 0.37764084, 0.38481620, 0.39199156, 0.39916691, 0.40634227, 0.41351759, 0.42069295, 0.42786831, 0.43504366, 0.44221902, 0.44939438, 0.45656973, 0.46374506, 0.47092041, 0.47809577, 0.48527113, 0.49244648, 0.49962184, 0.50685716, 0.51409578, 0.52133441, 0.52857304, 0.53581166, 0.54305035, 0.55028898, 0.55752760, 0.56476623, 0.57200485, 0.57924354, 0.58648217, 0.59372079, 0.60095942, 0.60819805, 0.61543667, 0.62267536, 0.62996829, 0.63728690, 0.64460552, 0.65192413, 0.65924275, 0.66656137, 0.67387998, 0.68119860, 0.68851727, 0.69583589, 0.70315450, 0.71047312, 0.71779174, 0.72511035, 0.73242897, 0.73974758, 0.74706620, 0.75810421, 0.77163076, 0.78515732, 0.79868382, 0.81221038, 0.82573694, 0.83926344, 0.85279000, 0.86631656, 0.88188213, 0.90110368, 0.92032516 }; // Major Scale const float calibMap2[QUAN_RES2] = { 0.01324014, 0.02853566, 0.03618342, 0.05147894, 0.06677447, 0.08206999, 0.08971775, 0.10501327, 0.12030879, 0.12775089, 0.14198242, 0.15621395, 0.17044549, 0.17756125, 0.19179279, 0.20602433, 0.21314010, 0.22737163, 0.24160317, 0.25587305, 0.26303557, 0.27736065, 0.29168573, 0.29884824, 0.31317332, 0.32749838, 0.34182346, 0.34898600, 0.36331105, 0.37764084, 0.38481620, 0.39916691, 0.41351759, 0.42786831, 0.43504366, 0.44939438, 0.46374506, 0.47092041, 0.48527113, 0.49962184, 0.51409578, 0.52133441, 0.53581166, 0.55028898, 0.55752760, 0.57200485, 0.58648217, 0.60095942, 0.60819805, 0.62267536, 0.63728690, 0.64460552, 0.65924275, 0.67387998, 0.68851727, 0.69583589, 0.71047312, 0.72511035, 0.73242897, 0.74706620, 0.77163076, 0.79868382, 0.81221038, 0.83926344, 0.86631656, 0.88188213, 0.92032516 }; // Dorian Scale const float calibMap3[QUAN_RES3] = { 0.01324014, 0.02853566, 0.04383118, 0.05147894, 0.06677447, 0.08206999, 0.08971775, 0.10501327, 0.12030879, 0.13486665, 0.14198242, 0.15621395, 0.17044549, 0.17756125, 0.19179279, 0.20602433, 0.22025587, 0.22737163, 0.24160317, 0.25587305, 0.26303557, 0.27736065, 0.29168573, 0.30601078, 0.31317332, 0.32749838, 0.34182346, 0.34898600, 0.36331105, 0.37764084, 0.39199156, 0.39916691, 0.41351759, 0.42786831, 0.43504366, 0.44939438, 0.46374506, 0.47809577, 0.48527113, 0.49962184, 0.51409578, 0.52133441, 0.53581166, 0.55028898, 0.56476623, 0.57200485, 0.58648217, 0.60095942, 0.60819805, 0.62267536, 0.63728690, 0.65192413, 0.65924275, 0.67387998, 0.68851727, 0.69583589, 0.71047312, 0.72511035, 0.73974758, 0.74706620, 0.77163076, 0.79868382, 0.81221038, 0.83926344, 0.86631656, 0.90110368, 0.92032516 }; // 5th const float calibMap4[QUAN_RES4] = { 0.01324014, 0.06677447, 0.12030879, 0.17044549, 0.22025587, 0.27019811, 0.32033587, 0.37047359, 0.42069295, 0.47092041, 0.52133441, 0.57200485, 0.62267536, 0.67387998, 0.72511035, 0.79868382, 0.90110368 }; // Whole tone const float calibMap5[QUAN_RES5] = { 0.01324014, 0.02853566, 0.04383118, 0.05912671, 0.07442223, 0.08971775, 0.10501327, 0.12030879, 0.13486665, 0.14909819, 0.16332972, 0.17756125, 0.19179279, 0.20602433, 0.22025587, 0.23448740, 0.24871893, 0.26303557, 0.27736065, 0.29168573, 0.30601078, 0.32033587, 0.33466092, 0.34898600, 0.36331105, 0.37764084, 0.39199156, 0.40634227, 0.42069295, 0.43504366, 0.44939438, 0.46374506, 0.47809577, 0.49244648, 0.50685716, 0.52133441, 0.53581166, 0.55028898, 0.56476623, 0.57924354, 0.59372079, 0.60819805, 0.62267536, 0.63728690, 0.65192413, 0.66656137, 0.68119860, 0.69583589, 0.71047312, 0.72511035, 0.73974758, 0.75810421, 0.78515732, 0.81221038, 0.83926344, 0.86631656, 0.90110368 }; //------------------------------------------------------------- // CV Meter Custom Character unsigned char str1[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F}; unsigned char str2[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x1F}; unsigned char str3[8] = {0x00,0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F}; unsigned char str4[8] = {0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F}; unsigned char str5[8] = {0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F,0x1F}; unsigned char str6[8] = {0x00,0x00,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F}; unsigned char str7[8] = {0x00,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F}; unsigned char str8[8] = {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F}; //------------------------------------------------------------- // Global Variables float gOSC_cv[8]; float gSeq_cv1[8]; float gSeq_cv2[8]; float gGlide; volatile 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] = {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; int bpm, _bpm; 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 { SeqCV((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); break; } else if (gCtrlSW[2] == 1 && gCtrlSW[3] == 0) { // Sequencer Mode2 (if gCtrlSW[2] ON) SeqCV((UpdateGate(bpm, N16TH, GATE1, 3, 0))); // Do shift ch 1~5 SeqCV((UpdateGate(bpm, N4TH, GATE2, 3, 0))); // Do shift ch 6 SeqCV((UpdateGate(bpm, NDOT4, GATE3, 3, 0))); // Do shift ch 7 SeqCV((UpdateGate(bpm, TRIP8, GATE4, 3, 0))); // Do shift ch 8 break; } else if (gCtrlSW[3] == 1) { // Sequencer Mode3 (if gCtrlSW[3] ON) // (ch6,7,8, short loop) SeqCV((UpdateGate(bpm, N16TH, GATE1, 3, 0))); // Do shift ch 1~5 SeqCV((UpdateGate(bpm, N8TH, GATE2, 3, 0))); // Do shift ch 6 SeqCV((UpdateGate(bpm, NDOT8, GATE3, 3, 0))); // Do shift ch 7 SeqCV((UpdateGate(bpm, TRIP4, GATE4, 3, 0))); // Do shift ch 8 break; } default: SetCV(); 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(); } //------------------------------------------------------------- // 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; // A880.0Hz gGATES[0] = gGATES[1] = gGATES[2] = gGATES[3] = 1; gLEDS[0] = gLEDS[1] = gLEDS[2] = gLEDS[3] = 1; UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]); break; } CVMeter(ch, &cv[ch]); ch++; ch &= 0x07; } //------------------------------------------------------------- // Sequence & Shift Out CV void SeqCV(int shift) { int i, j, k; static int ch, SeqMode; static int cnt1, cnt2, cnt3; static int cntloop1, cntloop2, cntloop3; static float glidecv[8]; unsigned int cv[8]; static float shiftcv[8]; static float buffercv[9]; static float loopcv[3]; 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[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(j = 1; j < 8; ++j) // Shift ch2~8 { shiftcv[j] = glidecv[j-1]; } ch++; ch &= 0x0F; } cnt1 = cnt2 = cnt3 = 0; } else if (gCtrlSW[2] == 1 && gCtrlSW[3] == 0) { // Sequencer Mode2 for(i = 1; i < 8; ++i) { glidecv[i] = glidecv[i] * gGlide + shiftcv[i] * (1.0f - gGlide); cv[i] = (unsigned int)glidecv[i]; UpdateCV(WRITE_UPDATE_N, i, &cv[i]); } if(shift == 1) // GATE1 { for(j = 1; j < 5; ++j) { shiftcv[j] = glidecv[j-1]; // Shift ch2~5 } ch++; ch &= 0x0F; } else if (shift == 2) { // GATE2 shiftcv[5] = glidecv[1]; // Shift ch6 } else if (shift == 3) { // GATE3 shiftcv[6] = glidecv[2]; // Shift ch7 } else if (shift == 4) { // GATE4 shiftcv[7] = glidecv[3]; // Shift ch8 } cnt1 = cnt2 = cnt3 = 0; } else if (gCtrlSW[3] == 1) { // Sequencer Mode3 for(i = 1; i < 5; ++i) { glidecv[i] = glidecv[i] * gGlide + shiftcv[i] * (1.0f - gGlide); cv[i] = (unsigned int)glidecv[i]; UpdateCV(WRITE_UPDATE_N, i, &cv[i]); } for(j = 5; j < 8; ++j) { glidecv[j] = glidecv[j] * gGlide + loopcv[j - 5] * (1.0f - gGlide); cv[j] = (unsigned int)glidecv[j]; UpdateCV(WRITE_UPDATE_N, j, &cv[j]); } if(shift == 1) // GATE1 { for(k = 1; k < 8; ++k) { shiftcv[k] = glidecv[k-1]; // Shift ch2~5 } ch++; ch &= 0x0F; } else if (shift == 2) { // GATE2 if(cnt1 < 4) { loopcv[0] = buffercv[cnt1] = shiftcv[4]; cnt1++; } else if (cnt1 >= 4) { loopcv[0] = buffercv[cntloop1]; cntloop1++; cntloop1 &= 0x03; } } else if (shift == 3) { // GATE3 if(cnt2 < 3) { loopcv[1] = buffercv[(cnt2 + 4)] = shiftcv[5]; cnt2++; } else if (cnt2 >= 3) { loopcv[1] = buffercv[(cntloop2 + 4)]; cntloop2++; cntloop2 &= 0x03; } } else if (shift == 4) { // GATE4 if(cnt3 < 2) { loopcv[2] = buffercv[(cnt3 + 7)] = shiftcv[6]; cnt3++; } else if (cnt3 >= 2) { loopcv[2] = buffercv[(cntloop3 + 7)]; cntloop3++; cntloop3 &= 0x01; } } if(gCtrlSW[1] == 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.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(); } //------------------------------------------------------------- // CV meter inline void CVMeter(int ch, const unsigned int *level) { unsigned int cvmeter; cvmeter = *level / (SCALING_N / 7.9f); gLCD.locate ( ch, 0 ); gLCD.putc(cvmeter); // put custom char } //------------------------------------------------------------- // Print LCD Mode Status void LCD() { switch(gMode) { case MODE_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]; 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; } // 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; } } } }