For MAX32630FTHR microcontroller: Plays piano notes in Nokia composer format text file placed in the SD card

Dependencies:   USBMSD_BD SDFileSystem max32630fthr USBDevice

Revision:
4:24086b80928e
Parent:
3:fcf745cd4f6d
Child:
5:8ba2f1e291b9
--- a/main.cpp	Wed Jul 17 06:11:33 2019 +0000
+++ b/main.cpp	Fri Jul 19 04:47:38 2019 +0000
@@ -3,11 +3,7 @@
 #include "USBSerial.h"
 #include "stdio.h"
 #include "SDFileSystem.h"
-
-//still needs BITS PER SAMPLE PARSING.
-//do this like so: PWM.write(WavValue/2^BPS)
-
-//MAPPING IS WRONG. P = 440 PLZ. Y = MIDDLE D.
+#include "ctype.h"
 
 #define BUFFER_SIZE 128
 #define HALF_BUFFER 64
@@ -22,16 +18,13 @@
 PwmOut PWM(P5_6);
 AnalogIn POT(AIN_0);
 volatile int bufferPOS = 0;
-volatile unsigned int g=0;
 
 Serial daplink(P2_1,P2_0);
 USBSerial microUSB;
-SDFileSystem sd(P0_5, P0_6, P0_4, P0_7, "sd");
 
 float audioDataBuffer[BUFFER_SIZE];
 
-struct WavFile
-{
+struct WavFile {
     long int size;
     int channels;
     int sampleRate;
@@ -47,10 +40,10 @@
 }
 
 int main()
-{   
+{
     WavFile Track;
     Ticker SampleTime;
-    
+
     daplink.printf("\f---DAPLINK SERIAL PORT---\r\n\r\nMINI PIANO PLAYER ver 1 \r\n\r\n\r\n");
     microUSB.printf("micro USB serial port\r\n");
     rLED = LED_ON;
@@ -60,7 +53,7 @@
     wait_ms(500);
     bLED = LED_ON;
     gLED = LED_OFF;
-    
+
     typedef enum {
         C2,Cs2,D2,Ds2,E2,F2,Fs2,G2,Gs2,A2,As2,B2,   //C2:0
         C3,Cs3,D3,Ds3,E3,F3,Fs3,G3,Gs3,A3,As3,B3,   //C3:12
@@ -69,43 +62,262 @@
         C6,Cs6,D6,Ds6,E6,F6,Fs6,G6,Gs6,             //C6:48
         rest,
         END
-    }pitchname;
-    
+    } pitchname;
+
     typedef struct {
-        float length;
+        int length;
         pitchname pitch;
     } note;
+
+    //input iterator vars
+    int i;
+    char c;
     
+    //input holder arrays
+    char buffer[256];
+    char inputtype[30];
+    typedef enum {
+        nokiacomposer,
+        normal
+    } inputtypes;
+    inputtypes current_inputtype;
+
+    //parse input type
+    int g;
+    tryagain:
+    printf("Please specify the input type.\r\nAvailable types:\r\nnokiacomposer\r\nnormal\r\n\r\n>");
+    for(i=0; i<30; i++) {
+        c=daplink.getc();
+        if(c == '\r')
+        {
+            g=i+2;
+            inputtype[i] = '\0';
+            break;
+        }
+        daplink.putc(c);
+        inputtype[i]=c;
+    }
+    printf("\r\n");
+    for(i=0;i<=g;i++)
+    {
+        printf("%i\t",inputtype[i]);
+    }
+    printf("\r\nSTRING LITERAL:\r\n");
+    char test[] = "nokiacomposer";
+    for(i=0;i<=g;i++)
+    {
+        printf("%i\t",test[i]);
+    }
+
+    if(!strcmp(inputtype,"nokiacomposer")) {
+        printf("\r\nType chosen: nokiacomposer\r\n");
+        current_inputtype = nokiacomposer;
+    } else if(!strcmp(inputtype,"normal")) {
+        printf("\r\nType chosen: normal\r\n");
+        current_inputtype = normal;
+    } else {
+        c=NULL;
+        printf("Invalid input type. Try again.");
+        goto tryagain; //prints message below input area
+    }
+
     //open file
-    
+toolarge:
+    printf("Please copy the text file of the song then right click on the PuTTY screen.\r\n");
+    for(i=0; 1; i++) { //do the loop at least once
+        c=daplink.getc();
+        daplink.putc(c);
+        buffer[i]=c;
+        if(i>=256) {
+            printf("Note data is greater than 2kB! Impossible. Try again.\033[A");
+            goto toolarge;
+        }
+        wait_ms(1); //wait for the next byte to arrive. every byte takes 1.04ms at 9600 baud.
+        if(!daplink.readable())
+        {
+            printf("That'sallll\r\n");
+            break;   
+        }
+    }
+    buffer[i] = ' '; //set EOF marker.
+    buffer[i++] = '\0';
+
+    //kunwari open na yung file
+    printf("\r\nFile recieved. Parsing...\r\n");
     //parse file into song in heap(remove sharps, put into enums.)
     
+    //useful benchmarks to find which characters are valid.
+    int candidate_number;
+    char *songpos=buffer+1; //song position
+    note song[256];
+    int pn_det;
+
+    if(current_inputtype == nokiacomposer) {
+        //for every [note] slot in [song]
+        for(i=0; i<2048; i++) {
+            //take the first base 10 integer you see.
+            //this initializes songpos ALWAYS. lol.
+            candidate_number = strtol(songpos-1,&songpos,10);
+            printf("Character:%i\r\n",candidate_number);
+            //if it's 1,2,4,8,16 or 32, VALID.
+            if((candidate_number==1)||candidate_number==2||candidate_number==4||candidate_number==8||candidate_number==16||candidate_number==32) {
+                song[i].length = candidate_number;
+                printf("Entered candidate [%i] into song[%i].length\r\n",candidate_number,i);
+            } else {
+                printf("Found invalid NOTE LENGTH value [%c] at position %li. Skipping until next whitespace...\r\n",*songpos,songpos-buffer);
+                //skip to after next whitespace
+                do {
+                    songpos++;
+                } while(!isspace(*(songpos)));
+                do {
+                    songpos++;
+                } while(!isalnum(*(songpos)));
+                //then do next iteration of LENGTH,PITCH,OCTAVE parse
+                i--;
+                continue;
+            }
+            //parse next character
+            printf("Character:%c\r\n",*songpos);
+            pn_det=0;
+            //watch out for sharps
+            if(!(*songpos=='#'||'a'<=*songpos<='z')) {
+                printf("Found invalid PITCH NAME value [%c] at position %li. Skipping word...\r\n",*songpos,songpos-buffer);
+                //skip to after next whitespace
+                do {
+                    songpos++;
+                } while(!isspace(*(songpos)));
+                do {
+                    songpos++;
+                } while(!isalnum(*(songpos)));
+                //then do next iteration of LENGTH,PITCH,OCTAVE parse
+                i--;
+                continue;
+            }
+            if(*songpos=='#') {
+                pn_det+=1;
+                songpos++;
+                printf("Sharp found.\r\n");
+            }
+            switch(*songpos) {
+                case 'c':
+                    pn_det+=0;
+                    break;
+                case 'd':
+                    pn_det+=2;
+                    break;
+                case 'e':
+                    pn_det+=4;
+                    break;
+                case 'f':
+                    pn_det+=5;
+                    break;
+                case 'g':
+                    pn_det+=7;
+                    break;
+                case 'a':
+                    pn_det+=9;
+                    break;
+                case 'b':
+                    pn_det+=11;
+                    break;
+            }
+            //check for invalid character at current position
+            //means that character was valid. move on.
+            songpos++;
+            printf("%c\n",*songpos);
+            if('0'<=*songpos<='9') {
+                int num = strtol(songpos,&songpos,10);
+                num+=3;//shift up thrice. board can't handle things this low.
+                printf("octave parsed: %i \t-> adder:%i\r\n",num,((num-2)*12));
+                pn_det=pn_det+((num-2)*12);
+            } else {
+                printf("Found invalid OCTAVE value [%c] at position %li. Skipping word...\r\n",*songpos,songpos-buffer);
+                //skip to after next whitespace
+                while(!isspace(*(songpos))) {
+                    songpos++;
+                }
+                while(!isalnum(*(songpos))) {
+                    songpos++;
+                }
+                //then do next iteration of LENGTH,PITCH,OCTAVE parse
+                i--;
+                continue;
+            }
+            song[i].pitch = (pitchname)pn_det;
+            printf("Entered pitch [%i] into song[%i].pitch\r\n",song[i].pitch,i);
+            printf("Final: {%i,%i} at i=%i\r\n",song[i].length,song[i].pitch,i);
+            printf("-------------------\r\n");
+            //make sure you're after the next whitespace
+            while(!isspace(*(songpos))) {
+                songpos++;
+            }
+            while(isspace(*(songpos))) {
+                songpos++;
+            };
+            if(*songpos == '\0'){
+                printf("NULL found. Escaping...\r\n");
+                goto esc;
+            }
+        }
+    } else if(current_inputtype == normal) {
+        //add normaltype parser here.
+    }
+
+    //add end term
+
+    //parsing is done
+esc:
+
+    printf("at end: i = %i\r\n",i);
+    i++;
+    song[i].length = 1;
+    song[i].pitch = END;
+    
+    printf("Parsing done.\r\n");
+    
+    //ENDOFPARSER
+    
+    int k;
+    for(k=0; song[k].pitch != END; k++) {
+        printf("{%i,%i},",song[k].length,song[k].pitch);
+    }
+    printf("{%i,%i},",song[k].length,song[k].pitch);
+    printf("\r\nPrinting done.\r\n");
+
     printf("Generating sine...\r\n");
-    int i;
-    for(i=0; i<128;i++)
-    {
+    for(i=0; i<128; i++) {
         audioDataBuffer[i] =((1.0 + sin((double(i)/16.0*6.28318530717959)))/2.0); //formula copied from mbed example
     }
+
+    /* HERE'S WHERE THE MUSIC STARTS */
+    /* LITERALLY. */
+
+    //FORMAT:  { NUM_BEATS, PITCH }
+    char bpminp[5];
+    int PlayingFreq;
+
+
+    printf("Please enter desired BPM:\r\n");
+
+    for(i=0; i<5 && c!='\r'; i++) {
+        c = daplink.getc();
+        daplink.putc(c);
+        bpminp[i] = c;
+    }
     
-    /* HERE'S WHERE THE MUSIC STARTS */
-    /* LITERALLY. */
+    printf("BPM Recieved.\r\n");
     
-    //FORMAT:  { NUM_BEATS, PITCH }
-    char c;
-    char bpminp[5];
-    int PlayingFreq;
-    
-    restart:
+    c=NULL; //reset C for next time.
+    int BPM = strtol(bpminp,NULL,0);
+    float SPB = 60*4/(float)BPM;
     
-    printf("Please enter desired BPM:\r\n");
+    printf("BPM: %i",BPM);
     
-    for(i=0;i<5 && c!='\r';i++)
-    {
-           c = daplink.getc();
-           bpminp[i] = c;
-    }
-    int BPM = strtol(bpminp,NULL,0);
-    float SPB = 60/(float)BPM;
+restart:
+
+    /*
+    HARVEST MOON SONG IN NORMAL FORMAT
+
     note song[] = {
         //batch 1
         {4,(pitchname)38},{4,E5},{4,Fs5},{4,D5},{4,Fs5},{4,G5},{4,A5},{4,Fs5},{4,D5},
@@ -124,11 +336,10 @@
         //END
         {1,END}
     };
-    
-    for(i = 0;1;i++)
-    {           
-        switch(song[i].pitch)
-        {
+    */
+
+    for(i = 0; 1; i++) {
+        switch(song[i].pitch) {
             case rest:
                 wait(song[i].length*SPB);
                 continue;
@@ -299,18 +510,25 @@
                 break;
             case END:
                 i = 0;
+                printf("SONG END. PRESS BUTTON TO RESTART.");
+                while(Button)
+                {
+                    printf("\033[A\033[A\033[A\033[A");
+                }
                 goto restart;
         }
-    
+
         Track.sampleRate = PlayingFreq * 16; //TONE FREQ = SAMPLE RATE / SAMPLES PER CYCLE
         PWM.period_us(1); //1MHz
         float ticker_period = (float) 1/(Track.sampleRate);
         printf("\r\nTicker Period: %f\tTicker Freq: %f\r\nTarget Freq: %i \r\n\r\n",ticker_period, 1/ticker_period, PlayingFreq);
 
         SampleTime.attach(&placeNewSample,ticker_period);
-        wait(song[i].length*SPB);
+        wait( (1/(float)song[i].length) *SPB);
         SampleTime.detach();
         
+        
+
         printf("\033[A\033[A\033[A\033[A");
     }
 }