Lawrence Quizon / Mbed OS mini_piano_player

Dependencies:   USBMSD_BD SDFileSystem max32630fthr USBDevice

main.cpp

Committer:
Lugs
Date:
2019-07-24
Revision:
11:df2fffa042b8
Parent:
10:97f600e6eae2
Child:
12:f9ce63d44ba7

File content as of revision 11:df2fffa042b8:

#include "mbed.h"
#include "max32630fthr.h"
#include "USBSerial.h"
#include "stdio.h"
#include "SDFileSystem.h"
#include "ctype.h"
#include "USBMSD_BD.h"
#include "SDBlockDevice.h"
#include "HeapBlockDevice.h"
#include "FATFileSystem.h"
#include "noteplayer.h"

#define BUFFER_SIZE 128
#define HALF_BUFFER 64
#define OS_MAINSTKSIZE 1024


bool debugState = 1;

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;
int i;

Serial daplink(P2_1,P2_0);
USBSerial microUSB;

float audioDataBuffer[BUFFER_SIZE];

// Physical block device, can be any device that supports the BlockDevice API
// HeapBlockDevice bd(512*BLOCK_SIZE, BLOCK_SIZE);
SDBlockDevice bd(P0_5, P0_6, P0_4, P0_7);

// File system declaration
FATFileSystem fs("fs");

// USB MSD
USBMSD_BD msd(&bd);

void clearSerialStream()
{
    char c;
    while(daplink.readable()) {
        c = daplink.getc();
        wait_ms(1);
    }
}

bool getInput(int maxSize,char *inputArray)
{
    int i;
    char c;
    clearSerialStream();
    for(i=0; i<maxSize && c!='\r'; i++) {
        c = daplink.getc();
        daplink.putc(c);
        inputArray[i] = c;
    }
    if(i == maxSize) {
        return 0;
    } else {
        return 1;
    }
}

// main() runs in its own thread in the OS
// (note the calls to Thread::wait below for delays)
void startFileSystem()
{
    printf("\f---STARTING FILESYSTEM...---\r\n");
    rLED = LED_ON;
    gLED = LED_ON;
    bLED = LED_OFF;

    Thread::wait(100);

    // Try to mount the filesystem
    printf("Mounting the filesystem... ");
    fflush(stdout);
    int err = fs.mount(&bd);
    printf("%s\r\n", (err ? "Fail :(" : "OK"));
    if (err) {
        // Reformat if we can't mount the filesystem
        // this should only happen on the first boot
        printf("No filesystem found, formatting... ");
        fflush(stdout);
        err = fs.reformat(&bd);
        printf("%s\r\n", (err ? "Fail :(" : "OK"));
    }

    rLED = LED_OFF;

    // Open the numbers file
    printf("Opening \"/fs/numbers.txt\"... ");
    fflush(stdout);
    FILE *f = fopen("/fs/numbers.txt", "r+");
    printf("%s\r\n", (!f ? "Fail :(" : "OK"));
    if (!f) {
        // Create the numbers file if it doesn't exist
        printf("No file found, creating a new file... ");
        fflush(stdout);
        f = fopen("/fs/numbers.txt", "w+");
        printf("%s\r\n", (!f ? "Fail :(" : "OK"));

        for (int i = 0; i < 10; i++) {
            printf("\rWriting numbers (%d/%d)... ", i, 10);
            fflush(stdout);
            err = fprintf(f, "    %d\r\n", i);
            if (err < 0) {
                printf("Fail :(\r\n");
            }
        }
        printf("\rWriting numbers (%d/%d)... OK\r\n", 10, 10);

        printf("Seeking file... ");
        fflush(stdout);
        err = fseek(f, 0, SEEK_SET);
        printf("%s\r\n", (err < 0 ? "Fail :(" : "OK"));
    }

    // Go through and increment the numbers
    for (int i = 0; i < 10; i++) {
        printf("\rIncrementing numbers (%d/%d)... ", i, 10);
        fflush(stdout);

        // Get current stream position
        long pos = ftell(f);

        // Parse out the number and increment
        int32_t number;
        fscanf(f, "%d", &number);
        number += 1;

        // Seek to beginning of number
        fseek(f, pos, SEEK_SET);

        // Store number
        fprintf(f, "    %d\r\n", number);
    }
    printf("\rIncrementing numbers (%d/%d)... OK\r\n", 10, 10);

    // Close the file which also flushes any cached writes
    printf("Closing \"/fs/numbers.txt\"... ");
    fflush(stdout);
    err = fclose(f);
    printf("%s\r\n", (err < 0 ? "Fail :(" : "OK"));

    // Display the root directory
    printf("Opening the root directory... ");
    fflush(stdout);
    DIR *d = opendir("/fs/");
    printf("%s\r\n", (!d ? "Fail :(" : "OK"));

    printf("root directory:\r\n");
    while (true) {
        struct dirent *e = readdir(d);
        if (!e) {
            break;
        }
        printf("    %s\r\n", e->d_name);
    }

    printf("Closing the root directory... ");
    fflush(stdout);
    err = closedir(d);
    printf("%s\r\n", (err < 0 ? "Fail :(" : "OK"));

    // Display the numbers file
    printf("Opening \"/fs/numbers.txt\"... ");
    fflush(stdout);
    f = fopen("/fs/numbers.txt", "r");
    printf("%s\r\n", (!f ? "Fail :(" : "OK"));

    printf("numbers:\r\n");
    while (!feof(f)) {
        int c = fgetc(f);
        printf("%c", c);
    }

    printf("\rClosing \"/fs/numbers.txt\"... ");
    fflush(stdout);
    err = fclose(f);
    printf("%s\r\n", (err < 0 ? "Fail :(" : "OK"));




    // Switch to MSD
//    printf("Unmounting... ");
//    fflush(stdout);
//    err = fs.unmount();
//    printf("%s\r\n", (err < 0 ? "Fail :(" : "OK"));


    printf("Starting MSD... ");
    msd.disk_initialize();
    err = msd.connect();
    bLED = LED_ON;
    printf("%s\r\n", (err < 0 ? "Fail :(" : "OK"));
}

float potval,reading;

void placeNewSample(void)
{
    PWM.write(audioDataBuffer[bufferPOS++]); //multiply by POT value for volume.
    bufferPOS = (bufferPOS+1) & 0x07F;
}

void presence()
{
    rLED = LED_ON;
    wait_ms(500);
    rLED = LED_OFF;
    gLED = LED_ON;
    wait_ms(500);
    bLED = LED_ON;
    gLED = LED_OFF;
}

char *skipToNextEntry(char *songpos, bool skiptype)
{
    if(skiptype == 0) {
        do {
            songpos++;
        } while(!isspace(*(songpos)));
        do {
            songpos++;
        } while(!isalnum(*(songpos)));
        return songpos;
    } else if(skiptype == 1) {
        while(!isspace(*(songpos))) {
            songpos++;
        }
        while(isspace(*(songpos))) {
            songpos++;
        };
    }
}

bool songParse(note *song,char *buffer)
{
    int candidate;
    char *songpos=buffer+1; //song position
    int pn_det;
    int i;
    for(i=0; i<256; i++) {
        //take the first base 10 integer you see.
        //this initializes songpos ALWAYS. lol.
        candidate = strtol(songpos-1,&songpos,10);

        if(debugState) {
            printf("Character:%i\r\n",candidate);
        }

        if(candidate == 0) {
            printf("Found invalid NOTE LENGTH value [%c] at position %li. Skipping until next whitespace...\r\n",*songpos,songpos-buffer);
            songpos = skipToNextEntry(songpos,0);
            i--;
            continue;
        } else {
            song[i].length = candidate;
            if(debugState) {
                printf("Entered candidate [%i] into song[%i].length\r\n",candidate,i);
            }
        }

        //parse next character
        if(debugState) {
            printf("Character:%c\r\n",*songpos);
        }

        pn_det=0;

        if(!(*songpos=='#'||'a'<=*songpos<='z'||*songpos=='-')) {
            printf("Found invalid PITCH NAME value [%c] at position %li. Skipping word...\r\n",*songpos,songpos-buffer);
            songpos = skipToNextEntry(songpos,0);
            i--;
            continue;
        }
        if(*songpos=='#') { //watch out for sharps
            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;
            case '-':
                pn_det=57;
                break;
        }

        songpos++;
        if('0'<=*songpos<='9') {
            int num = strtol(songpos,&songpos,10);
            num+=3; //nokia composer octaves are usually much too low.
            if(debugState) {
                printf("octave parsed: %i \t-> adder:%i\r\n",num,((num-2)*12));
            }
            pn_det=pn_det+((num-2)*12);
        } else if (*songpos != '-') {
            printf("Found invalid OCTAVE value [%c] at position %li. Skipping word...\r\n",*songpos,songpos-buffer);
            songpos = skipToNextEntry(songpos,0);
            i--; //rewrite current note
            continue;
        }
        song[i].pitch = (pitchname)pn_det;
        
        if(debugState) {
            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");
        }

        songpos = skipToNextEntry(songpos,1);

        //check for buffer end
        if(*(songpos) == '\0') {
            i++;
            song[i].length = 1;
            song[i].pitch = END;
            printf("Parsing done. i = %i\r\n",i);
            return 1;
        }
        if(songpos-buffer > 2048) {
            printf("songpos exceeded buffer size.\r\n");
            return 0;
        }
    }
    printf("Song exceeded maximum number of notes.\r\n");
    return 0;
}

void printSong(note *song)
{
    for(i=0; song[i].pitch != END; i++) {
        printf("{%i,%i},",song[i].length,song[i].pitch);
    }
    printf("{%i,%i},",song[i].length,song[i].pitch);
    printf("\r\nPrinting done.\r\n");
}

int main()
{
    Ticker SampleTime;

    startFileSystem();

    daplink.printf("\f---DAPLINK SERIAL PORT---\r\n\r\nMINI PIANO PLAYER ver 2 \r\n\r\n\r\n");
    microUSB.printf("micro USB serial port\r\n");
    presence();

    char *title = new char[24];
    title[0] = '/';
    title[1] = 'f';
    title[2] = 's';
    title[3] = '/';
    FILE *txtfile;
    char *buffer = new char[1024];
    while(1) {
        printf("Please input filename: ");
        char *inputptr = title+4;
        if(!getInput(24,inputptr)) {
            printf("Filenames cannot be more than 20 characters.\033[A\r\n");
        }
        txtfile = fopen(title,"r");
        if(txtfile == NULL) {
            printf("File not found. Please append filetype at the end of filename.\033[A\r\n");
            continue;
        }
        break;
    }

    fseek(txtfile,0L,SEEK_END);
    int size = ftell(txtfile);
    fseek(txtfile,0,SEEK_SET);
    fread(buffer,1,size,txtfile);
    printf("Printing file...\r\n");
    for(int i=0; i<size; i++) {
        printf("%c",buffer[i]);
    }
    buffer[i] = ' ';
    buffer[i+1] = '\0';
    buffer[i+2] = 'a';

    printf("\r\nFile recieved. Parsing...\r\n");

    note song[1024];
    if(!songParse(song,buffer)) {
        printf("Song parse unsuccessful.\r\n");
        return 0;
    }
    printSong(song);

    printf("Generating sine...\r\n");
    for(int i=0; i<128; i++) {
        audioDataBuffer[i] =((1.0 + sin((double(i)/16.0*6.28318530717959)))/2.0); //formula copied from mbed example
    }

    char bpminp[5];
    printf("Please enter desired BPM:\r\n");
    getInput(5,bpminp);
    int BPM = strtol(bpminp,NULL,0);
    float SPB = 60*4/(float)BPM;

    int sampleRate;
    int PlayingFreq;
    for(int i = 0; 1; i++) {
        PlayingFreq = pitch2freq(song[i].pitch);
        if(PlayingFreq == -1) {
            i = 0;
            printf("SONG END. PRESS BUTTON TO RESTART.");
            while(Button) {
                wait_ms(2);
            }
        } else if(PlayingFreq == 0) { //rest
            wait((1/(float)song[i].length)*SPB);
        } else {
            sampleRate = PlayingFreq * 16;
            PWM.period_us(1); //1MHz
            float ticker_period = (float) 1/(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");
        }
    }
}