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