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
Diff: main.cpp
- Revision:
- 5:e305509d53f3
- Parent:
- 4:b9f5ae574447
- Child:
- 6:5796b63c70ef
--- a/main.cpp Sat Jan 19 12:03:20 2013 +0000 +++ b/main.cpp Sat Jan 26 02:04:03 2013 +0000 @@ -35,23 +35,23 @@ //------------------------------------------------------------- // 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 (VCO Tuning) +#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 QUAN_RES1 116 // Quantize voltage Steps +#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 MODE_NUM 8 // Modes - #define SPI_RATE 40000000 // 40Mbps SPI Clock #define SCALING_N 38400.0 #define INPUT_PORT 12345 // Input Port Number @@ -59,16 +59,16 @@ #define POLLING_INTERVAL 20 // Polling Interval (us) //------------------------------------------------------------- -// DAC8568 Control Bits +// 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 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 CLR 0x05 // Clear Code Register #define WRITE_LDAC_REG 0x06 -#define RESET 0x07 // Software Reset DAC8568 +#define RESET 0x07 // Software Reset DAC8568 #define SETUP_INTERNAL_REF 0x08 //------------------------------------------------------------- @@ -76,15 +76,44 @@ #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(void); -void CheckSW(void); +void SeqCV(int); +void CheckModeSW(void); void CVMeter(int, const unsigned int*); void LCD(); void WriteCustomChar(unsigned char, unsigned char*); @@ -161,27 +190,27 @@ // 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.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 +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 }; @@ -204,10 +233,13 @@ static float gSeq_cv1[8]; static float gSeq_cv2[8]; static float gGlide; -static float gCtrl[2]; -unsigned int gCtrlSW[2]; unsigned int gMode; +// Variables for Control + +float gCtrl[2]; +unsigned int gCtrlSW[4]; + //------------------------------------------------------------- // mbed Functions @@ -219,7 +251,7 @@ DigitalOut gGATES[4] = {p22, p23, p24, p25}; // GateOut DigitalOut gLEDS[4] = {p18, p19, p20, p21}; // LED -DigitalOut gCLOCKOUT(p25); // ClockOut +DigitalOut gCLOCKOUT(p26); // ClockOut AnalogIn gAIN(p17); // Glide Potentiometer InterruptIn gSW(p30); // Mode SW @@ -237,6 +269,8 @@ int main() { float pot, _pot; + int bpm, _bpm; + int shift1, shift2, shift3, shift4; if(SetupEthNetIf() == -1) { @@ -245,10 +279,11 @@ gLEDS[i] = 1; wait(0.25); } + return -1; } - // mdns (Bonjour) +// mdns (Bonjour) HTTPServer svr; mDNSResponder mdns; @@ -261,15 +296,16 @@ pot = _pot = 0; gGlide = gMode = 0; + bpm = _bpm = 120; LCD(); gLCD.locate( 0, 1 ); gLCD.printf("12345678 G>>%3.2f", gGlide); - // loop +// loop while(1) { - gGlide = pot = gAIN.read(); + gGlide = pot = gAIN.read(); // Glide Value if(abs(pot - _pot) > 0.01f) { @@ -279,9 +315,58 @@ _pot = gAIN.read(); } - if(gMode == MODE_SEQ) + if(gMode == MODE_SEQ) // Mode Sequencer & Shift Register { - SeqCV(); + if(gCtrlSW[0] == 1) // Stop (gCtrlSW[0]) + { + bpm = 0; + + } else { + + 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; + } + + 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 + + } 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 + + } 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 + } } else { @@ -303,7 +388,7 @@ void InitOSCCV() { - // write custom char LCD CGRAM +// write custom char LCD CGRAM WriteCustomChar(0x00, str1); WriteCustomChar(0x01, str2); WriteCustomChar(0x02, str3); @@ -313,17 +398,17 @@ WriteCustomChar(0x06, str7); WriteCustomChar(0x07, str8); - // Init. SPI +// Init. SPI gLDAC = _ENABLE; - gSPI.format(8,1); // Data word length 8bit, Mode=1 + gSPI.format(8,1); // Data word length 8bit, Mode=1 gSPI.frequency(SPI_RATE); - UpdateCV(CLR, 0, 0); // Ignore CLR Pin + UpdateCV(CLR, 0, 0); // Ignore CLR Pin - gSW.mode(PullUp); // Use internal pullup for ModeSW + gSW.mode(PullUp); // Use internal pullup for ModeSW wait(.001); - gSW.rise(&CheckSW); // InterruptIn rising edge(ModeSW) + gSW.rise(&CheckModeSW); // InterruptIn rising edge(ModeSW) gPoller.attach_us(&NetPoll, POLLING_INTERVAL); // Ticker Polling wait(0.2); @@ -376,6 +461,134 @@ } //------------------------------------------------------------- +// 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() @@ -461,7 +674,10 @@ 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; } @@ -475,39 +691,21 @@ //------------------------------------------------------------- // Sequence & Shift Out CV -void SeqCV() +void SeqCV(int shift) { static int ch; - static int count; + static int cnt1, cnt2, cnt3; + static int cntloop1, cntloop2, cntloop3; static unsigned 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; - static float clock; - static float time; - - SeqMode = (unsigned int)(gCtrl[1] * (MODE_NUM - 3)); // Sequencer Quantize Mode - - time = gTimer.read(); - clock = gCtrl[0] * 0.5 + 0.01; - - gLEDS[0] = gGATES[0] = 0; // Trigger - - if(time > (clock / 2)) - { - gLEDS[1] = gGATES[1] = 0; // Gate - } else if (count % 2) { - - gLEDS[2] = gGATES[2] = 0; - - } else if (count % 3) { - - gLEDS[3] = gGATES[3] = 0; - count = 0; - } + SeqMode = (unsigned int)(gCtrl[1] * (MODE_NUM - 3)); // Sequencer Quantize Mode (gCtrl[1]) switch(SeqMode) { @@ -623,31 +821,140 @@ break; } - for(int i = 1; i < 8; ++i) + if((gCtrlSW[2] == 0 || gCtrlSW[2] == 1) && gCtrlSW[3] == 0) { - glidecv[i] = glidecv[i] * gGlide + shiftcv[i] * (1.0f - gGlide); - cv[i] = (unsigned int)glidecv[i]; + for(int 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]); + } - UpdateCV(WRITE_UPDATE_N, i, &cv[i]); + } else if (gCtrlSW[3] == 1) { + + for(int 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(int 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(time > clock) + if(gCtrlSW[2] == 0 && gCtrlSW[3] == 0) // Sequencer Mode1 { - gLEDS[0] = gGATES[0] = 1; - gLEDS[1] = gGATES[1] = 1; - gLEDS[2] = gGATES[2] = 1; - gLEDS[3] = gGATES[3] = 1; + if(shift == 1) // GATE1 + { + for(int i = 1; i < 8; ++i) // Shift ch2~8 + { + shiftcv[i] = glidecv[i-1]; + } - count++; - - for(int j = 1; j < 8; ++j) // Shift Note - { - shiftcv[j] = glidecv[j-1]; + ch++; + ch &= 0x0F; } - ch++; - ch &= 0x0F; - gTimer.reset(); + cnt1 = cnt2 = cnt3 = 0; + + } else if (gCtrlSW[2] == 1 && gCtrlSW[3] == 0) { // Sequencer Mode2 + + if(shift == 1) // GATE1 + { + for(int 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 + + if(shift == 1) // GATE1 + { + for(int 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) @@ -663,9 +970,9 @@ //------------------------------------------------------------- // Check SW -void CheckSW() +void CheckModeSW() { - wait(0.01); + wait(0.02); if(gMode < MODE_NUM - 1) { @@ -676,6 +983,18 @@ 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(); } @@ -686,15 +1005,14 @@ { unsigned int cvmeter; - cvmeter = *level / 4860; - // cvmeter = *level / (SCALING_N / 7.9); + cvmeter = *level / (SCALING_N / 7.9); gLCD.locate ( ch, 0 ); gLCD.putc(cvmeter); // put custom char } //------------------------------------------------------------- -// Print LCD Menu +// Print LCD Mode Status void LCD() { @@ -733,8 +1051,6 @@ case MODE_SEQ: gLCD.locate( 9, 0 ); gLCD.printf("ASRSEQ "); - - gTimer.start(); // Sequencer Timer Start break; case MODE_Calb: @@ -822,14 +1138,12 @@ if(isdigit(msg[0].address[len-1])) num = msg[0].address[len-1] - '0' - 1; - else - num = -1; unsigned int absv = msg[2].f + 0; //convert -0 to 0 - // address pattern SYNC & GATE (Type Tag int, float) + // address pattern SYNC & GATE (Type Tag int, float) if((strncmp(msg[0].address+(len-1)-4, "sync", 4)==0) && (num == -1)) { if(num > 1) break; if(absv >= 1 || msg[2].i >= 1) gCLOCKOUT = 1; @@ -841,7 +1155,7 @@ if(absv >= 1 || msg[2].i >= 1) gLEDS[num] = gGATES[num] = 1; else gLEDS[num] = gGATES[num] = 0; break; - // (touchOSC Control push, toggle) + // (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; @@ -893,21 +1207,21 @@ 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 controller + // address pattern for control if ((strncmp(msg[0].address+(len-1)-6, "ctrlsw", 6)==0) && (num != -1)) { - if(num > 2) break; + if(num > 4) break; if(absv >= 1 || msg[2].i >= 1) gCtrlSW[num] = 1; else gCtrlSW[num] = 0; break;