Radio Junk Box / Mbed 2 deprecated KAMUI_USBHOST_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 /*
00008 Copyright (c) 2010 Peter Barrett
00009 
00010 Permission is hereby granted, free of charge, to any person obtaining a copy
00011 of this software and associated documentation files (the "Software"), to deal
00012 in the Software without restriction, including without limitation the rights
00013 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00014 copies of the Software, and to permit persons to whom the Software is
00015 furnished to do so, subject to the following conditions:
00016 
00017 The above copyright notice and this permission notice shall be included in
00018 all copies or substantial portions of the Software.
00019 
00020 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00021 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00022 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00023 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00024 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00025 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00026 THE SOFTWARE.
00027 */
00028 
00029 #include "mbed.h"
00030 #include "TextLCD.h"
00031 #include "USBHost.h"
00032 #include "Utils.h"
00033 #include "FATFileSystem.h"
00034 #include <stdlib.h>
00035 #include <math.h>
00036 
00037 int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize);
00038 int MassStorage_Read(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize);
00039 int MassStorage_Write(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize);
00040 
00041 class USBFileSystem : public FATFileSystem
00042 {
00043     int _device;
00044     u32 _blockSize;
00045     u32 _blockCount;
00046     
00047 public:
00048     USBFileSystem() : FATFileSystem("usb"),_device(0),_blockSize(0),_blockCount(0)
00049     {
00050     }
00051     
00052     void SetDevice(int device)
00053     {
00054         _device = device;
00055     }
00056     
00057     virtual int disk_initialize()
00058     {
00059         return MassStorage_ReadCapacity(_device,&_blockCount,&_blockSize);
00060     }
00061     
00062     virtual int disk_write(const char *buffer, int block_number)
00063     {
00064         return MassStorage_Write(_device,block_number,1,(u8*)buffer,_blockSize);
00065     }
00066     
00067     virtual int disk_read(char *buffer, int block_number)
00068     {
00069         return MassStorage_Read(_device,block_number,1,(u8*)buffer,_blockSize);
00070     }
00071         
00072     virtual int disk_sectors()
00073     {
00074         return _blockCount;
00075     }
00076 };
00077 
00078 void DumpFS(int depth, int count)
00079 {
00080     DIR *d = opendir("/usb");
00081     if (!d)
00082     {
00083         printf("USB file system borked\n");
00084         return;
00085     }
00086 
00087     printf("\nDumping root dir\n");
00088     struct dirent *p;
00089     for(;;)
00090     {
00091         p = readdir(d);
00092         if (!p)
00093             break;
00094         int len = sizeof( dirent);
00095         printf("%s %d\n", p->d_name, len);
00096     }
00097     closedir(d);
00098 }
00099 
00100 int OnDiskInsert(int device)
00101 {
00102     USBFileSystem fs;
00103     fs.SetDevice(device);
00104     DumpFS(0,0);
00105     return 0;
00106 }
00107 
00108 /*
00109     Simple test shell to exercise mouse,keyboard,mass storage and hubs.
00110     Add 2 15k pulldown resistors between D+/D- and ground, attach a usb socket and have at it.
00111 */
00112 
00113 Serial pc(USBTX, USBRX);
00114 int GetConsoleChar()
00115 {
00116     if (!pc.readable())
00117         return -1;
00118     char c = pc.getc();
00119     pc.putc(c); // echo
00120     return c;
00121 }
00122 
00123 //-------------------------------------------------------------
00124 // Define
00125 
00126 #define AD5551                      // 14bitDAC
00127 
00128 #define SPI_RATE            1000000 // 1Mbps
00129 #define MIDI_RATE           31250   // 31.25kbps
00130 #define BEEP_FREQ           1760.0  // 1760Hz
00131 #define UPDATE_INTERVAL     100     // 100us
00132 #define SW_WATCH_INTERVAL   (25000/UPDATE_INTERVAL) // 25ms
00133 #define PARAM_GLIDE         6554.0
00134 #define PARAM_DP            6912.0  // UPDATE_INTERVAL = 100us
00135 //#define PARAM_DP            8192.0  // UPDATE_INTERVAL = 50us
00136 
00137 #define UPDATE_MODE0        0       // Update Interval CV ch1-6 1200us, ch7,8 400us
00138 #define UPDATE_MODE1        1       // Update Interval CV ch1-6 N/A,    ch7,8 200us
00139 
00140 #define GATE1               0x01
00141 #define GATE2               0x02
00142 #define GATE3               0x04
00143 #define GATE4               0x08
00144 
00145 #define SYNC1CLK            0x01
00146 #define SYNC1RUN            0x02
00147 #define SYNC2CLK            0x04
00148 #define SYNC2RUN            0x08
00149 
00150 #define MODE_CV             0x00
00151 #define MODE_GATE           0x40
00152 #define MODE_SYNC           0x80
00153 #define MODE_SET_SYNC       0xC0
00154 
00155 #define SW1                 0x01
00156 #define SW2                 0x02
00157 #define SW3                 0x04
00158 #define SW4                 0x08
00159 #define SYNC1CLK_IN         0x10
00160 #define SYNC1RUN_IN         0x20
00161 #define SYNC2CLK_IN         0x40
00162 #define GATE_IN             0x80
00163 
00164 #define _ENABLE             0
00165 #define _DISABLE            1
00166 
00167 #define BUFSIZE             32  // size of ring buffer (ex 4,8,16,32...)
00168 #define LFO_WF_TRI          0
00169 #define LFO_WF_SQR          1
00170 #define LFO_WF_SAW          2
00171 #define LFO_WF_NONE         3
00172 #define MINIMUMNOTE         12
00173 #define SYNC_TURN_TIME      (5000/UPDATE_INTERVAL)  // 5ms          
00174 
00175 #define MENULOOP_INTERVAL   25000    // 25ms
00176 
00177 //-------------------------------------------------------------
00178 // Functions
00179 
00180 void            MenuLoop(void);
00181 void            InitKamui(void);
00182 void            UpdateCV(void);
00183 unsigned char   CheckSW(unsigned char);
00184 
00185 void            RcvMIDI(void);
00186 void            GetMIDI(void);
00187 void            MidiCV(void);
00188 void            CalcHzVTbl(void);
00189 unsigned short  OctVtoHzV(unsigned short);
00190 void            DinSync(void);
00191 extern void     MIDI_Parser(unsigned char);
00192 
00193 //-------------------------------------------------------------
00194 // Global Variables
00195 
00196 int gUpdateMode;
00197 unsigned short gCV[8];
00198 unsigned char  gGATE;
00199 unsigned char  gSYNC;
00200 unsigned char  gSW;
00201 
00202 union {
00203     unsigned short    WORD;    
00204     struct {
00205         unsigned char L;
00206         unsigned char H; 
00207     } BYTE;
00208 } gDAC;
00209 
00210 int             gPtr_buf_in, gPtr_buf_out;
00211 unsigned char   gRxBuf[BUFSIZE];
00212 
00213 float           gGLIDE[4];
00214 unsigned short  gLFO_DP[4];
00215 unsigned char   gLFO_FORM[4];
00216 unsigned char   gMIDI_CH[4];
00217 short           gTblHzV[3072];
00218 
00219 extern unsigned char    gPlayNoteBuf[];
00220 extern unsigned char    gGateBuf[];
00221 extern unsigned char    gPitchBendBuf[];
00222 extern unsigned char    gModWheelBuf[];
00223 extern unsigned char    gMIDISYNC_CLK;
00224 extern unsigned char    gMIDISYNC_RUN;
00225 
00226 int pot[4],_pot[4];
00227 unsigned char mode = 7; // for Intialize
00228 unsigned char edit[4];
00229 int val[2][4] = { 0, 0, 0, 0, 50, 50, 50, 50 };
00230 char *wave[4] = { "TR","SQ","SW","--" };
00231 
00232 //-------------------------------------------------------------
00233 // mbed Functions
00234 
00235 // TextLCD
00236 TextLCD gLCD(p23, p24, p25, p26, p29, p30); // rs, e, d4-d7
00237 
00238 // SPI
00239 SPI gSPI(p11,p12,p13);
00240 DigitalOut gCSA(p14);
00241 DigitalOut gCSB(p22);
00242 
00243 // Sirial MIDI
00244 Serial gMIDI(p9,p10);
00245 
00246 // AnalogIn
00247 AnalogIn    gAIN1(p15);   // VR1
00248 AnalogIn    gAIN2(p16);   // VR2
00249 AnalogIn    gAIN3(p17);   // VR3
00250 AnalogIn    gAIN4(p18);   // VR4
00251 AnalogIn    gAIN5(p19);   // IN1
00252 AnalogIn    gAIN6(p20);   // IN2
00253 
00254 // BEEP
00255 PwmOut gBEEP(p21);
00256 
00257 // LED
00258 DigitalOut gLED1(LED1);
00259 DigitalOut gLED2(LED2);
00260 DigitalOut gLED3(LED3);
00261 DigitalOut gLED4(LED4);
00262 BusOut gLEDS(LED1,LED2,LED3,LED4);
00263 
00264 // Ticker
00265 Ticker gTICKER;
00266 Ticker gTICKER2;
00267 
00268 //  Implemented in TestShell.cpp
00269 void TestShell();
00270 void USBInit();
00271 
00272 //-------------------------------------------------------------
00273 // main
00274 
00275 int main() {
00276 
00277     int i;
00278 
00279     USBInit();
00280 
00281     // Initialize
00282     gPtr_buf_in = gPtr_buf_out = 0;
00283     for( i=0; i<4; i++) {
00284         pot[i] = _pot[i] = 0;
00285         edit[i] = 0;
00286         gGLIDE[i] = 1.0 / expf(val[0][i]*656.0/PARAM_GLIDE);
00287         gLFO_DP[i] = expf(val[1][i]*656.0/PARAM_DP); 
00288         gLFO_FORM[i] = LFO_WF_TRI;
00289         gMIDI_CH[i] = i; 
00290     }
00291     
00292     for( i=0; i<16; i++) {  // MIDI Data Buffers
00293         gPlayNoteBuf[i] =24;
00294         gGateBuf[i] = 0;
00295         gPitchBendBuf[i] = 0x40;
00296         gModWheelBuf[i] = 0;        
00297     }
00298     
00299     gSW = 1; // for Intialize
00300     
00301     CalcHzVTbl();
00302     InitKamui();
00303     gTICKER2.attach_us(&MenuLoop, MENULOOP_INTERVAL);
00304     TestShell();
00305 }
00306 
00307 //-------------------------------------------------------------
00308 // Menu LOOP
00309 void MenuLoop()
00310 {
00311     int i;
00312     static unsigned char ch;
00313 
00314     // Read pot
00315     pot[0] =  gAIN1.read_u16();
00316     pot[1] =  gAIN2.read_u16();
00317     pot[2] =  gAIN3.read_u16();
00318     pot[3] =  gAIN4.read_u16();
00319         
00320     // change pot amount?
00321     if(abs(pot[ch] - _pot[ch]) > 0x2000) edit[ch] = 1;
00322 
00323     if(edit[ch]) {
00324         switch(mode) {
00325             case 0:
00326                 gGLIDE[ch] = 1.0 / expf(pot[ch]/PARAM_GLIDE);
00327                 val[0][ch] = pot[ch] / 656;
00328                 break;
00329             case 1:
00330                 gLFO_DP[ch] = expf(pot[ch]/PARAM_DP);
00331                 val[1][ch] = pot[ch] / 656;
00332                 break;
00333             case 2:
00334                 gLFO_FORM[ch] = pot[ch] / 0x4000;
00335                 break;
00336             case 3:
00337                 gMIDI_CH[ch] = pot[ch] / 0x1000;
00338                 break;
00339             default:
00340                 break;
00341         }
00342     }
00343         
00344     // Push Mode SW
00345     if(gSW & SW1) {
00346         mode++;
00347         mode &= 0x03;                      
00348         for( i=0; i<4; i++) {
00349             _pot[i] = pot[i];
00350             edit[i] = 0;
00351         }
00352     }
00353         gSW = 0;
00354 
00355     // LCD Display
00356     gLCD.locate( 0, 1 );
00357     switch(mode) {
00358         case 0:
00359             gLCD.printf("GLID %02d %02d %02d %02d",
00360             val[0][0], val[0][1], val[0][2], val[0][3]);
00361             break;
00362         case 1:
00363             gLCD.printf("FREQ %02d %02d %02d %02d",
00364             val[1][0], val[1][1], val[1][2], val[1][3]);
00365             break;
00366         case 2:
00367             gLCD.printf("FORM %s %s %s %s",
00368             wave[gLFO_FORM[0]], wave[gLFO_FORM[1]],
00369             wave[gLFO_FORM[2]], wave[gLFO_FORM[3]]); 
00370             break;
00371         case 3:
00372             gLCD.printf("MIDI %02d %02d %02d %02d",
00373             gMIDI_CH[0]+1, gMIDI_CH[1]+1,
00374             gMIDI_CH[2]+1, gMIDI_CH[3]+1);
00375             break;
00376     }
00377 
00378     ch++;
00379     ch &= 0x03;
00380 }
00381 
00382 //-------------------------------------------------------------
00383 // Initialize KAMUI
00384 
00385 void InitKamui()
00386 {
00387     // Init. Variables
00388     for( int i=0; i<8; i++) {
00389         gCV[i] = 0x8000;
00390     }
00391     gGATE = 0;
00392     gSYNC = 0;
00393 
00394     gUpdateMode = UPDATE_MODE0;
00395   
00396     // Init. SPI
00397     gCSA = _DISABLE;
00398     gCSB = _DISABLE;
00399     gSPI.format(8,0);
00400     gSPI.frequency(SPI_RATE);
00401 
00402     // Init. Serial MIDI
00403     gMIDI.baud(MIDI_RATE);
00404     
00405     // Ticker
00406     gTICKER.attach_us(&UpdateCV, UPDATE_INTERVAL);
00407 
00408     // Beep
00409     gBEEP.period(1.0/BEEP_FREQ);
00410     gBEEP.write(0.5);
00411     wait(0.2);
00412     gBEEP.write(0.0);
00413 
00414     // Init Display
00415     gLCD.locate( 0, 0 );
00416               // 123456789ABCDEF
00417     gLCD.printf("USBHOST MIDI-CV");
00418 }
00419 
00420 //-------------------------------------------------------------
00421 // Update CV, GATE, SYNC
00422 
00423 void UpdateCV()
00424 { 
00425     unsigned char rcv,ch;
00426     unsigned char ptn[] = { 0,1,6,7,2,3,6,7,4,5,6,7 };
00427     const int numptn = (sizeof ptn / sizeof ptn[0]) - 1;
00428     static unsigned char  cnt;
00429 
00430     // SET DAC 
00431     ch = ptn[cnt];
00432     if(gUpdateMode) ch |= 0x06;
00433 
00434 #ifdef AD5551 // 14bitDAC
00435     gDAC.WORD = gCV[ch] >> 2;
00436 #else
00437     gDAC.WORD = gCV[ch];    
00438 #endif
00439     
00440     gCSA = _ENABLE;
00441     gSPI.write(gDAC.BYTE.H);
00442     gSPI.write(gDAC.BYTE.L);
00443     gCSA = _DISABLE;        
00444 
00445     // GATE or SYNC OUT
00446     if(cnt & 0x01) {
00447         // GATE OUT
00448         gCSB = _ENABLE;
00449         rcv = gSPI.write(gGATE | MODE_GATE) & 0x0F;
00450         gCSB = _DISABLE;
00451     }
00452     else {
00453         // SYNC OUT
00454         gCSB = _ENABLE;
00455         rcv = gSPI.write(gSYNC | MODE_SYNC);
00456         gCSB = _DISABLE;
00457     }
00458 
00459     // SEL CV CHANNEL
00460     gCSB = _ENABLE;
00461     gSPI.write(ch);
00462     gCSB = _DISABLE;
00463 
00464     cnt < numptn ? cnt++ : cnt = 0;
00465 
00466     gSW |= CheckSW(rcv);
00467     RcvMIDI();
00468     GetMIDI();
00469     DinSync();
00470     MidiCV();
00471 }
00472 
00473 //-------------------------------------------------------------
00474 // Check SW
00475 
00476 unsigned char CheckSW(unsigned char c) {
00477 
00478     static unsigned char  swbuf[2];
00479     static unsigned int   cntsw;
00480     unsigned char ret = 0;
00481 
00482     if(cntsw > SW_WATCH_INTERVAL) {
00483         if(c &= 0x0F) {
00484             if(!swbuf[1]) {
00485                 if( swbuf[0] == c) {
00486                     swbuf[1] = c;
00487                     ret = c;
00488                 }
00489                 else {
00490                     swbuf[0] = c;
00491                 }
00492             }
00493         }
00494         else {
00495             swbuf[1] = 0;
00496             swbuf[0] = 0;
00497         }
00498         cntsw = 0;
00499     }
00500     cntsw++;
00501     return ret;
00502 }
00503 
00504 //-------------------------------------------------------------
00505 // Receive MIDI Data & Store Ring Buffer
00506 
00507 void RcvMIDI() {
00508 
00509     if(!gMIDI.readable()) return;
00510 
00511     gPtr_buf_in++;
00512     gPtr_buf_in &= (BUFSIZE - 1);
00513     gRxBuf[gPtr_buf_in] = gMIDI.getc();
00514 }
00515 
00516 //-------------------------------------------------------------
00517 // Get MIDI Data from Ring Buffer
00518 
00519 void GetMIDI() {
00520     unsigned char rb;
00521 
00522     // ring buffer empty?
00523     if(gPtr_buf_in != gPtr_buf_out) {
00524         // get 1byte from ring buffer
00525         gPtr_buf_out++;
00526         gPtr_buf_out &= (BUFSIZE - 1);
00527         rb = gRxBuf[gPtr_buf_out];
00528         MIDI_Parser(rb);
00529         gMIDI.putc(rb);
00530     }
00531 }
00532 
00533 //-------------------------------------------------------------
00534 // MIDI Data to CV, GATE
00535 
00536 void MidiCV()
00537 {
00538     static unsigned char ch;
00539     static unsigned short phase[4];
00540     static float cvf[4];
00541     int lfo,mod;
00542     unsigned char midi_ch;
00543     unsigned int cv;
00544     unsigned int note;
00545     
00546     midi_ch = gMIDI_CH[ch];
00547 
00548     note = gPlayNoteBuf[midi_ch];
00549     if( note < MINIMUMNOTE) note = MINIMUMNOTE;
00550     note -= MINIMUMNOTE;
00551 
00552     // DDS Phase
00553     phase[ch] += gLFO_DP[ch];
00554 
00555     // LFO DDS Genelator
00556     switch(gLFO_FORM[ch]) {
00557         case    LFO_WF_TRI:
00558             if(phase[ch] < 32738)  lfo = phase[ch] - 16384;
00559             else                   lfo = (16383 + 32768) - phase[ch];
00560             break;
00561         case    LFO_WF_SQR:
00562             if(phase[ch] < 32738)  lfo = 32767;
00563             else                   lfo = 0;
00564             break;
00565         case    LFO_WF_SAW:
00566             lfo = phase[ch] / 2 - 16384;
00567             break;
00568         default :
00569             lfo = 0;
00570             break;
00571     }
00572 
00573     // Modulation amount
00574     mod = lfo * gModWheelBuf[midi_ch] >> 8;                
00575 
00576     // Calculate CV
00577     cvf[ch]  = ((float)(note << 8) - cvf[ch]) * gGLIDE[ch] + cvf[ch];       
00578     cv = (unsigned int)cvf[ch] + (0x8000 - (0x0040 << 3))
00579             + (gPitchBendBuf[midi_ch] << 2) + mod;
00580     if(cv > 0xFFFF) cv = 0xFFFF;
00581     gCV[ch] = (unsigned short)cv;
00582     gCV[ch+4] = OctVtoHzV(gCV[ch]);
00583 
00584     // GATE
00585     gGateBuf[midi_ch] ? gGATE |= (1<<ch) : gGATE &= ~(1<<ch);
00586 
00587     ch++;
00588     ch &= 0x03;
00589 }
00590 
00591 //-------------------------------------------------------------
00592 // Oct/V to Hz/V Converter
00593 
00594 void CalcHzVTbl() // Calc Conv. Table
00595 {
00596     int i;
00597     float v;
00598 
00599     for( i=0; i<3072; i++) {
00600         v = 24576.0 * pow(2.0,(i/3072.0));
00601         gTblHzV[i] = (unsigned short)v;
00602     }
00603 }
00604 
00605 unsigned short OctVtoHzV( unsigned short vin)
00606 {
00607     int oct,res;
00608     unsigned short vout;
00609 
00610     if(vin > 0xE400) vin = 0xE400;  // Maximum Note E8   Vin = 10.794V
00611     if(vin < 0x6800) vin = 0x6800;  // Minimum Note C-2  Vin = -2.000V
00612     vin -= 0x6800;
00613 
00614     oct = vin / 0xC00; // 0xC00 : 3072 
00615     res = vin % 0xC00;
00616 
00617     vout = ((unsigned short)gTblHzV[res] >> (10 - oct)) + 0x8000;
00618     return vout;
00619 } 
00620 
00621 //-------------------------------------------------------------
00622 // DIN SYNC Control
00623 
00624 void DinSync()
00625 {
00626     static unsigned int  cnt;
00627     static unsigned int  cnt24 = 10;
00628 
00629     if(gMIDISYNC_RUN) gSYNC |= (SYNC1RUN | SYNC2RUN);
00630     else gSYNC &= ~(SYNC1RUN | SYNC2RUN);
00631 
00632     if(cnt >= SYNC_TURN_TIME) gSYNC &= ~(SYNC1CLK | SYNC2CLK);
00633 
00634     if(gMIDISYNC_CLK) {
00635         gSYNC |= (SYNC1CLK | SYNC2CLK);
00636         gMIDISYNC_CLK = 0;
00637         cnt = 0;
00638         cnt24++;
00639     }
00640     if(cnt24 >= 24) cnt24 = 0;
00641 
00642     gLED3 = gSYNC & SYNC1RUN ? 1 : 0;
00643     gLED4 = cnt24 < 4 ? 1 : 0;
00644     
00645     cnt++;
00646 }