KAMUI USB MIDI-CV Example

Dependencies:   TextLCD mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

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 }