For MAX32630FTHR microcontroller: Plays piano notes in Nokia composer format text file placed in the SD card
Dependencies: USBMSD_BD SDFileSystem max32630fthr USBDevice
main.cpp
- Committer:
- Lugs
- Date:
- 2019-07-19
- Revision:
- 4:24086b80928e
- Parent:
- 3:fcf745cd4f6d
- Child:
- 5:8ba2f1e291b9
File content as of revision 4:24086b80928e:
#include "mbed.h" #include "max32630fthr.h" #include "USBSerial.h" #include "stdio.h" #include "SDFileSystem.h" #include "ctype.h" #define BUFFER_SIZE 128 #define HALF_BUFFER 64 DigitalOut rLED(LED1); DigitalOut gLED(LED2); DigitalOut bLED(LED3); DigitalIn Button(P2_3); MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3); PwmOut PWM(P5_6); AnalogIn POT(AIN_0); volatile int bufferPOS = 0; Serial daplink(P2_1,P2_0); USBSerial microUSB; float audioDataBuffer[BUFFER_SIZE]; struct WavFile { long int size; int channels; int sampleRate; int bitsPerSample; }; float potval,reading; void placeNewSample(void) { PWM.write(audioDataBuffer[bufferPOS++]); //multiply by POT value for volume. bufferPOS = (bufferPOS+1) & 0x07F; } 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; wait_ms(500); rLED = LED_OFF; gLED = LED_ON; 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 C4,Cs4,D4,Ds4,E4,F4,Fs4,G4,Gs4,A4,As4,B4, //C4:24 C5,Cs5,D5,Ds5,E5,F5,Fs5,G5,Gs5,A5,As5,B5, //C5:36 C6,Cs6,D6,Ds6,E6,F6,Fs6,G6,Gs6, //C6:48 rest, END } pitchname; typedef struct { 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"); 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; } printf("BPM Recieved.\r\n"); c=NULL; //reset C for next time. int BPM = strtol(bpminp,NULL,0); float SPB = 60*4/(float)BPM; printf("BPM: %i",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}, {4,A5},{4,B5},{4,A5},{4,G5},{4,B5},{4,A5}, {4,rest}, //batch 2 {4,D5},{4,E5},{4,Fs5},{4,D5},{4,Fs5},{4,G5},{4,A5},{4,Fs5},{4,D5}, {4,A5},{4,G5},{4,D5},{4,Fs5},{4,D5},{4,E5}, {4,rest}, //batch 1 {4,D5},{4,E5},{4,Fs5},{4,D5},{4,Fs5},{4,G5},{4,A5},{4,Fs5},{4,D5}, {4,A5},{4,B5},{4,A5},{4,G5},{4,B5},{4,A5}, {4,rest}, //batch 3 {2,G5},{4,G5},{4,E5},{4,Fs5},{4,E5},{4,D5},{4,Cs5},{4,D5}, //END {1,END} }; */ for(i = 0; 1; i++) { switch(song[i].pitch) { case rest: wait(song[i].length*SPB); continue; case D2: PlayingFreq = 73; break; case Ds2: PlayingFreq = 78; break; case E2: PlayingFreq = 82; break; case F2: PlayingFreq = 87; break; case Fs2: PlayingFreq = 92; break; case G2: PlayingFreq = 98; break; case Gs2: PlayingFreq = 104; break; case A2: PlayingFreq = 110; break; case As2: PlayingFreq = 117; break; case B2: PlayingFreq = 123; break; case C3: PlayingFreq = 131; break; case Cs3: PlayingFreq = 139; break; case D3: PlayingFreq = 147; break; case Ds3: PlayingFreq = 156; break; case E3: PlayingFreq = 165; break; case F3: PlayingFreq = 175; break; case Fs3: PlayingFreq = 185; break; case G3: PlayingFreq = 196; break; case Gs3: PlayingFreq = 208; break; case A3: PlayingFreq = 220; break; case As3: PlayingFreq = 233; break; case B3: PlayingFreq = 247; break; case C4: PlayingFreq = 262; break; case Cs4: PlayingFreq = 277; break; case D4: PlayingFreq = 294; break; case Ds4: PlayingFreq = 311; break; case E4: PlayingFreq = 330; break; case F4: PlayingFreq = 349; break; case Fs4: PlayingFreq = 370; break; case G4: PlayingFreq = 392; break; case Gs4: PlayingFreq = 415; break; case A4: PlayingFreq = 440; break; case As4: PlayingFreq = 466; break; case B4: PlayingFreq = 494; break; case C5: PlayingFreq = 523; break; case Cs5: PlayingFreq = 554; break; case D5: PlayingFreq = 587; break; case Ds5: PlayingFreq = 622; break; case E5: PlayingFreq = 659; break; case F5: PlayingFreq = 698; break; case Fs5: PlayingFreq = 740; break; case G5: PlayingFreq = 784; break; case Gs5: PlayingFreq = 831; break; case A5: PlayingFreq = 880; break; case As5: PlayingFreq = 932; break; case B5: PlayingFreq = 988; break; case C6: PlayingFreq = 1047; break; case Cs6: PlayingFreq = 1109; break; case D6: PlayingFreq = 1175; break; case Ds6: PlayingFreq = 1245; break; case E6: PlayingFreq = 1319; break; case F6: PlayingFreq = 1397; break; case Fs6: PlayingFreq = 1480; break; case G6: PlayingFreq = 1568; break; case Gs6: PlayingFreq = 1661; 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( (1/(float)song[i].length) *SPB); SampleTime.detach(); printf("\033[A\033[A\033[A\033[A"); } }