Radio Junk Box
/
KMAUI_USBMIDI-CV_Example
KAMUI USB MIDI-CV Example
Embed:
(wiki syntax)
Show/hide line numbers
main.cpp
00001 //------------------------------------------------------------- 00002 // KAMUI USBMIDI-CV Exapmple 00003 // Copyright (C) 2012 RJB RadioJunkBox 00004 // Released under the MIT License: http://mbed.org/license/mit 00005 //------------------------------------------------------------- 00006 00007 #include "mbed.h" 00008 #include "TextLCD.h" 00009 #include "USBMIDI.h" 00010 #include <stdlib.h> 00011 #include <math.h> 00012 00013 //------------------------------------------------------------- 00014 // Define 00015 00016 #define AD5551 // 14bitDAC 00017 00018 #define SPI_RATE 1000000 // 1Mbps 00019 #define MIDI_RATE 31250 // 31.25kbps 00020 #define BEEP_FREQ 1760.0 // 1760Hz 00021 #define UPDATE_INTERVAL 100 // 100us 00022 #define SW_WATCH_INTERVAL (25000/UPDATE_INTERVAL) // 25ms 00023 #define PARAM_GLIDE 6554.0 00024 #define PARAM_DP 6912.0 // UPDATE_INTERVAL = 100us 00025 //#define PARAM_DP 8192.0 // UPDATE_INTERVAL = 50us 00026 00027 #define UPDATE_MODE0 0 // Update Interval CV ch1-6 1200us, ch7,8 400us 00028 #define UPDATE_MODE1 1 // Update Interval CV ch1-6 N/A, ch7,8 200us 00029 00030 #define GATE1 0x01 00031 #define GATE2 0x02 00032 #define GATE3 0x04 00033 #define GATE4 0x08 00034 #define GATE_LED5 0x10 00035 00036 #define SYNC1CLK 0x01 00037 #define SYNC1RUN 0x02 00038 #define SYNC2CLK 0x04 00039 #define SYNC2RUN 0x08 00040 00041 #define MODE_CV 0x00 00042 #define MODE_GATE 0x40 00043 #define MODE_SYNC 0x80 00044 #define MODE_SET_SYNC 0xC0 00045 00046 #define SW1 0x01 00047 #define SW2 0x02 00048 #define SW3 0x04 00049 #define SW4 0x08 00050 #define SYNC1CLK_IN 0x10 00051 #define SYNC1RUN_IN 0x20 00052 #define SYNC2CLK_IN 0x40 00053 #define GATE_IN 0x80 00054 00055 #define _ENABLE 0 00056 #define _DISABLE 1 00057 00058 #define BUFSIZE 32 // size of ring buffer (ex 4,8,16,32...) 00059 #define LFO_WF_TRI 0 00060 #define LFO_WF_SQR 1 00061 #define LFO_WF_SAW 2 00062 #define LFO_WF_NONE 3 00063 #define MINIMUMNOTE 12 00064 #define SYNC_TURN_TIME (5000/UPDATE_INTERVAL) // 5ms 00065 00066 //------------------------------------------------------------- 00067 // Functions 00068 00069 void InitKamui(void); 00070 void UpdateCV(void); 00071 unsigned char CheckSW(unsigned char); 00072 00073 void RcvMIDI(void); 00074 void RcvUSBMIDI(MIDIMessage); 00075 void MidiCV(void); 00076 void CalcHzVTbl(void); 00077 unsigned short OctVtoHzV(unsigned short); 00078 void DinSync(void); 00079 extern void MIDI_Parser(unsigned char); 00080 00081 //------------------------------------------------------------- 00082 // Global Variables 00083 00084 int gUpdateMode; 00085 unsigned short gCV[8]; 00086 unsigned char gGATE; 00087 unsigned char gSYNC; 00088 unsigned char gSW; 00089 00090 union { 00091 unsigned short WORD; 00092 struct { 00093 unsigned char L; 00094 unsigned char H; 00095 } BYTE; 00096 } gDAC; 00097 00098 int gPtr_buf_in, gPtr_buf_out; 00099 unsigned char gRxBuf[BUFSIZE]; 00100 00101 float gGLIDE[4]; 00102 unsigned short gLFO_DP[4]; 00103 unsigned char gLFO_FORM[4]; 00104 unsigned char gMIDI_CH[4]; 00105 short gTblHzV[3072]; 00106 00107 extern unsigned char gPlayNoteBuf[]; 00108 extern unsigned char gGateBuf[]; 00109 extern unsigned char gPitchBendBuf[]; 00110 extern unsigned char gModWheelBuf[]; 00111 extern unsigned char gMIDISYNC_CLK; 00112 extern unsigned char gMIDISYNC_RUN; 00113 00114 //------------------------------------------------------------- 00115 // mbed Functions 00116 00117 // TextLCD 00118 TextLCD gLCD(p23, p24, p25, p26, p29, p30); // rs, e, d4-d7 00119 00120 // SPI 00121 SPI gSPI(p11,p12,p13); 00122 DigitalOut gCSA(p14); 00123 DigitalOut gCSB(p22); 00124 00125 // Sirial MIDI 00126 // Serial gMIDI(p9,p10); 00127 00128 // AnalogIn 00129 AnalogIn gAIN1(p15); // VR1 00130 AnalogIn gAIN2(p16); // VR2 00131 AnalogIn gAIN3(p17); // VR3 00132 AnalogIn gAIN4(p18); // VR4 00133 AnalogIn gAIN5(p19); // IN1 00134 AnalogIn gAIN6(p20); // IN2 00135 00136 // BEEP 00137 PwmOut gBEEP(p21); 00138 00139 // LED 00140 DigitalOut gLED1(LED1); 00141 DigitalOut gLED2(LED2); 00142 DigitalOut gLED3(LED3); 00143 DigitalOut gLED4(LED4); 00144 BusOut gLEDS(LED1,LED2,LED3,LED4); 00145 00146 // Ticker 00147 Ticker gTICKER; 00148 00149 //USBMIDI object 00150 USBMIDI gUSBMIDI; 00151 00152 //------------------------------------------------------------- 00153 // main 00154 00155 int main() { 00156 00157 int i; 00158 int pot[4],_pot[4]; 00159 unsigned char rb; 00160 unsigned char ch = 0; 00161 unsigned char mode = 7; // for Intialize 00162 unsigned char edit[4]; 00163 int val[2][4] = { 0, 0, 0, 0, 50, 50, 50, 50 }; 00164 char *wave[4] = { "TR","SQ","SW","--" }; 00165 00166 // Initialize 00167 gPtr_buf_in = gPtr_buf_out = 0; 00168 for( i=0; i<4; i++) { 00169 pot[i] = _pot[i] = 0; 00170 edit[i] = 0; 00171 gGLIDE[i] = 1.0 / expf(val[0][i]*656.0/PARAM_GLIDE); 00172 gLFO_DP[i] = expf(val[1][i]*656.0/PARAM_DP); 00173 gLFO_FORM[i] = LFO_WF_TRI; 00174 gMIDI_CH[i] = i; 00175 } 00176 00177 for( i=0; i<16; i++) { // MIDI Data Buffers 00178 gPlayNoteBuf[i] =24; 00179 gGateBuf[i] = 0; 00180 gPitchBendBuf[i] = 0x40; 00181 gModWheelBuf[i] = 0; 00182 } 00183 00184 gSW = 1; // for Intialize 00185 00186 CalcHzVTbl(); 00187 InitKamui(); 00188 00189 // loop 00190 while(1) { 00191 00192 // ring buffer empty? 00193 if(gPtr_buf_in != gPtr_buf_out) { 00194 00195 // get 1byte from ring buffer 00196 gPtr_buf_out++; 00197 gPtr_buf_out &= (BUFSIZE - 1); 00198 rb = gRxBuf[gPtr_buf_out]; 00199 MIDI_Parser(rb); 00200 continue; 00201 } 00202 00203 // Read pot 00204 pot[0] = gAIN1.read_u16(); 00205 pot[1] = gAIN2.read_u16(); 00206 pot[2] = gAIN3.read_u16(); 00207 pot[3] = gAIN4.read_u16(); 00208 00209 // change pot amount? 00210 if(abs(pot[ch] - _pot[ch]) > 0x2000) edit[ch] = 1; 00211 00212 if(edit[ch]) { 00213 switch(mode) { 00214 case 0: 00215 gGLIDE[ch] = 1.0 / expf(pot[ch]/PARAM_GLIDE); 00216 val[0][ch] = pot[ch] / 656; 00217 break; 00218 case 1: 00219 gLFO_DP[ch] = expf(pot[ch]/PARAM_DP); 00220 val[1][ch] = pot[ch] / 656; 00221 break; 00222 case 2: 00223 gLFO_FORM[ch] = pot[ch] / 0x4000; 00224 break; 00225 case 3: 00226 gMIDI_CH[ch] = pot[ch] / 0x1000; 00227 break; 00228 default: 00229 break; 00230 } 00231 } 00232 00233 // Push Mode SW 00234 if(gSW & SW1) { 00235 mode++; 00236 mode &= 0x03; 00237 for( i=0; i<4; i++) { 00238 _pot[i] = pot[i]; 00239 edit[i] = 0; 00240 } 00241 } 00242 gSW = 0; 00243 00244 // LCD Display 00245 gLCD.locate( 0, 1 ); 00246 switch(mode) { 00247 case 0: 00248 gLCD.printf("GLID %02d %02d %02d %02d", 00249 val[0][0], val[0][1], val[0][2], val[0][3]); 00250 break; 00251 case 1: 00252 gLCD.printf("FREQ %02d %02d %02d %02d", 00253 val[1][0], val[1][1], val[1][2], val[1][3]); 00254 break; 00255 case 2: 00256 gLCD.printf("FORM %s %s %s %s", 00257 wave[gLFO_FORM[0]], wave[gLFO_FORM[1]], 00258 wave[gLFO_FORM[2]], wave[gLFO_FORM[3]]); 00259 break; 00260 case 3: 00261 gLCD.printf("MIDI %02d %02d %02d %02d", 00262 gMIDI_CH[0]+1, gMIDI_CH[1]+1, 00263 gMIDI_CH[2]+1, gMIDI_CH[3]+1); 00264 break; 00265 } 00266 00267 ch++; 00268 ch &= 0x03; 00269 } 00270 } 00271 00272 //------------------------------------------------------------- 00273 // Initialize KAMUI 00274 00275 void InitKamui() 00276 { 00277 // Init. Variables 00278 for( int i=0; i<8; i++) { 00279 gCV[i] = 0x8000; 00280 } 00281 gGATE = 0; 00282 gSYNC = 0; 00283 00284 gUpdateMode = UPDATE_MODE0; 00285 00286 // Init. SPI 00287 gCSA = _DISABLE; 00288 gCSB = _DISABLE; 00289 gSPI.format(8,0); 00290 gSPI.frequency(SPI_RATE); 00291 00292 // Call Back for USBMIDI Messages Received 00293 gUSBMIDI.attach(RcvUSBMIDI); 00294 00295 // Ticker 00296 gTICKER.attach_us(&UpdateCV, UPDATE_INTERVAL); 00297 00298 // Beep 00299 gBEEP.period(1.0/BEEP_FREQ); 00300 gBEEP.write(0.5); 00301 wait(0.2); 00302 gBEEP.write(0.0); 00303 00304 // Init Display 00305 gLCD.locate( 0, 0 ); 00306 // 123456789ABCDEF 00307 gLCD.printf("USBMIDI-CV Exam"); 00308 } 00309 00310 //------------------------------------------------------------- 00311 // Update CV, GATE, SYNC 00312 00313 void UpdateCV() 00314 { 00315 unsigned char rcv,ch; 00316 unsigned char ptn[] = { 0,1,6,7,2,3,6,7,4,5,6,7 }; 00317 const int numptn = (sizeof ptn / sizeof ptn[0]) - 1; 00318 static unsigned char cnt; 00319 00320 __disable_irq(); 00321 00322 // SET DAC 00323 ch = ptn[cnt]; 00324 if(gUpdateMode) ch |= 0x06; 00325 00326 #ifdef AD5551 // 14bitDAC 00327 gDAC.WORD = gCV[ch] >> 2; 00328 #else 00329 gDAC.WORD = gCV[ch]; 00330 #endif 00331 00332 gCSA = _ENABLE; 00333 gSPI.write(gDAC.BYTE.H); 00334 gSPI.write(gDAC.BYTE.L); 00335 gCSA = _DISABLE; 00336 00337 // GATE or SYNC OUT 00338 if(cnt & 0x01) { 00339 // GATE OUT 00340 gCSB = _ENABLE; 00341 rcv = gSPI.write(gGATE | MODE_GATE) & 0x0F; 00342 gCSB = _DISABLE; 00343 } 00344 else { 00345 // SYNC OUT 00346 gCSB = _ENABLE; 00347 rcv = gSPI.write(gSYNC | MODE_SYNC); 00348 gCSB = _DISABLE; 00349 } 00350 00351 // SEL CV CHANNEL 00352 gCSB = _ENABLE; 00353 gSPI.write(ch); 00354 gCSB = _DISABLE; 00355 00356 cnt < numptn ? cnt++ : cnt = 0; 00357 00358 __enable_irq(); 00359 00360 gSW |= CheckSW(rcv); 00361 DinSync(); 00362 MidiCV(); 00363 } 00364 00365 //------------------------------------------------------------- 00366 // Check SW 00367 00368 unsigned char CheckSW(unsigned char c) { 00369 00370 static unsigned char swbuf[2]; 00371 static unsigned int cntsw; 00372 unsigned char ret = 0; 00373 00374 if(cntsw > SW_WATCH_INTERVAL) { 00375 if(c &= 0x0F) { 00376 if(!swbuf[1]) { 00377 if( swbuf[0] == c) { 00378 swbuf[1] = c; 00379 ret = c; 00380 } 00381 else { 00382 swbuf[0] = c; 00383 } 00384 } 00385 } 00386 else { 00387 swbuf[1] = 0; 00388 swbuf[0] = 0; 00389 } 00390 cntsw = 0; 00391 } 00392 cntsw++; 00393 return ret; 00394 } 00395 00396 //------------------------------------------- 00397 // Receive USBMIDI Data & Store Ring Buffer 00398 void RcvUSBMIDI(MIDIMessage msg) { 00399 00400 if(msg.data[0] == 0) return; 00401 00402 // gGATE ^= GATE_LED5; 00403 // printf("%02x %02x %02x %02x\r\n",msg.data[0],msg.data[1],msg.data[2],msg.data[3]); 00404 00405 for( int i=1; i<4; i++) { 00406 gPtr_buf_in++; 00407 gPtr_buf_in &= (BUFSIZE - 1); 00408 gRxBuf[gPtr_buf_in] = msg.data[i]; 00409 } 00410 } 00411 00412 //------------------------------------------------------------- 00413 // MIDI Data to CV, GATE 00414 00415 void MidiCV() 00416 { 00417 static unsigned char ch; 00418 static unsigned short phase[4]; 00419 static float cvf[4]; 00420 int lfo,mod; 00421 unsigned char midi_ch; 00422 unsigned int cv; 00423 unsigned int note; 00424 00425 midi_ch = gMIDI_CH[ch]; 00426 00427 note = gPlayNoteBuf[midi_ch]; 00428 if( note < MINIMUMNOTE) note = MINIMUMNOTE; 00429 note -= MINIMUMNOTE; 00430 00431 // DDS Phase 00432 phase[ch] += gLFO_DP[ch]; 00433 00434 // LFO DDS Genelator 00435 switch(gLFO_FORM[ch]) { 00436 case LFO_WF_TRI: 00437 if(phase[ch] < 32738) lfo = phase[ch] - 16384; 00438 else lfo = (16383 + 32768) - phase[ch]; 00439 break; 00440 case LFO_WF_SQR: 00441 if(phase[ch] < 32738) lfo = 32767; 00442 else lfo = 0; 00443 break; 00444 case LFO_WF_SAW: 00445 lfo = phase[ch] / 2 - 16384; 00446 break; 00447 default : 00448 lfo = 0; 00449 break; 00450 } 00451 00452 // Modulation amount 00453 mod = lfo * gModWheelBuf[midi_ch] >> 7; 00454 00455 // Calculate CV 00456 cvf[ch] = ((float)(note << 8) - cvf[ch]) * gGLIDE[ch] + cvf[ch]; 00457 cv = (unsigned int)cvf[ch] + (0x8000 - (0x0040 << 3)) 00458 + (gPitchBendBuf[midi_ch] << 2) + mod; 00459 if(cv > 0xFFFF) cv = 0xFFFF; 00460 gCV[ch] = (unsigned short)cv; 00461 gCV[ch+4] = OctVtoHzV(gCV[ch]); 00462 00463 // GATE 00464 gGateBuf[midi_ch] ? gGATE |= (1<<ch) : gGATE &= ~(1<<ch); 00465 00466 ch++; 00467 ch &= 0x03; 00468 } 00469 00470 //------------------------------------------------------------- 00471 // Oct/V to Hz/V Converter 00472 00473 void CalcHzVTbl() // Calc Conv. Table 00474 { 00475 int i; 00476 float v; 00477 00478 for( i=0; i<3072; i++) { 00479 v = 24576.0 * pow(2.0,(i/3072.0)); 00480 gTblHzV[i] = (unsigned short)v; 00481 } 00482 } 00483 00484 unsigned short OctVtoHzV( unsigned short vin) 00485 { 00486 int oct,res; 00487 unsigned short vout; 00488 00489 if(vin > 0xE400) vin = 0xE400; // Maximum Note E8 Vin = 10.794V 00490 if(vin < 0x6800) vin = 0x6800; // Minimum Note C-2 Vin = -2.000V 00491 vin -= 0x6800; 00492 00493 oct = vin / 0xC00; // 0xC00 : 3072 00494 res = vin % 0xC00; 00495 00496 vout = ((unsigned short)gTblHzV[res] >> (10 - oct)) + 0x8000; 00497 return vout; 00498 } 00499 00500 //------------------------------------------------------------- 00501 // DIN SYNC Control 00502 00503 void DinSync() 00504 { 00505 static unsigned int cnt; 00506 static unsigned int cnt24 = 10; 00507 00508 if(gMIDISYNC_RUN) gSYNC |= (SYNC1RUN | SYNC2RUN); 00509 else gSYNC &= ~(SYNC1RUN | SYNC2RUN); 00510 00511 if(cnt >= SYNC_TURN_TIME) gSYNC &= ~(SYNC1CLK | SYNC2CLK); 00512 00513 if(gMIDISYNC_CLK) { 00514 gSYNC |= (SYNC1CLK | SYNC2CLK); 00515 gMIDISYNC_CLK = 0; 00516 cnt = 0; 00517 cnt24++; 00518 } 00519 if(cnt24 >= 24) cnt24 = 0; 00520 00521 gLED3 = gSYNC & SYNC1RUN ? 1 : 0; 00522 gLED4 = cnt24 < 4 ? 1 : 0; 00523 00524 cnt++; 00525 }
Generated on Sat Jul 16 2022 12:03:52 by 1.7.2