Big Mouth Billy Bass player that takes raw wavefiles and decision list text files from an SD card
Dependencies: SDFileSystem mbed BillyBass
main.cpp
- Committer:
- bikeNomad
- Date:
- 2013-06-05
- Revision:
- 0:0944c3654ded
- Child:
- 1:f3f439154ab4
File content as of revision 0:0944c3654ded:
#include "mbed.h" #include "SDFileSystem.h" #include <list> #include <cmath> #define SD_NAME "sd" #define SD_ROOT "/" SD_NAME #define BASS_DIRECTORY SD_ROOT // Power: // Power GND J9/14 // Vin (6V) J9/16 // Digital: DigitalOut tail(PTA13); // J3/2 DigitalOut mouth(PTC12); // J3/1 DigitalOut head(PTC13); // J3/3 DigitalIn pushbutton(PTD5); // J3/4 PwmOut redLED(LED_RED); PwmOut greenLED(LED_GREEN); PwmOut blueLED(LED_BLUE); // Analog: // GND J3/14 // VrefH J3/16 AnalogOut speaker(PTE30); // J10/11 // PTD0 D10 – Used for CS of SPI // PTD2 D11 – Used for MOSI of SPI // PTD3 D12 – Used for MISO of SPI // PTC5 J1/9 Used for SCLK of SPI // MOSI, MISO, SCLK, CS, name SDFileSystem sd(PTD2, PTD3, PTC5, PTD0, SD_NAME); Serial pc(USBTX, USBRX); typedef int16_t Sample_t; // 16-bit raw, LE samples const size_t BUFFER_SIZE = 512; const float SAMPLE_RATE_HZ = 8000.0; const size_t SAMPLES_PER_BUFFER = BUFFER_SIZE / sizeof(Sample_t); const float SECONDS_PER_CHUNK = SAMPLES_PER_BUFFER / SAMPLE_RATE_HZ; struct Action { float actionTime; bool desiredState; DigitalOut *output; bool operator < (Action const &other) const { return actionTime < other.actionTime; } bool isValid() { return actionTime >= 0.0 && output != 0; } Action() : actionTime(-1.0), desiredState(false), output(0) { } bool parseLine(char const *line) { // TODO return true; } }; #define MAX_BASENAME_LENGTH 30 #define MAX_ACTION_LINE_LENGTH 100 struct Song { char basename[ MAX_BASENAME_LENGTH + 1 ]; unsigned sequenceNumber; unsigned whichFish; std::list<Action> actions; Song() : sequenceNumber(0), whichFish(3) { basename[0] = 0; } bool readWaveFile(char const *_waveFileName) { if (!parseFilename(_waveFileName, sequenceNumber, whichFish, basename)) return false; char txtFileName[ FILENAME_MAX ]; sprintf(txtFileName, "%u_%u_%s.txt", sequenceNumber, whichFish, basename); FILE *txtfile = fopen(txtFileName, "rt"); if (!txtfile) return false; // TODO // read actions from file char actionLine[ MAX_ACTION_LINE_LENGTH + 1 ]; while (fgets(actionLine, sizeof(actionLine), txtfile)) { Action action; if (action.parseLine(actionLine)) { actions.push_back(action); } } return true; } static bool parseFilename(char const *_name, unsigned &_num1, unsigned &_num2, char *_basename) { char basename[ MAX_BASENAME_LENGTH + 1 ]; unsigned num1, num2; char extension[ 4 ]; int nItems = sscanf(_name, "%u_%u_%30[^_.].%3[a-zA-Z]", &num1, &num2, basename, extension); if (nItems != 4) return false; if (num2 > 2) return false; if (strcasecmp("raw", extension)) return false; _num1 = num1; _num2 = num2; strcpy(_basename, basename); return true; } // return true if filename is of proper format // <num>_<num>_<name>.raw // and there is a corresponding .txt file static bool isValidWaveFileName(char const *_name) { unsigned int num1, num2; char basename[ 31 ]; return parseFilename(_name, num1, num2, basename); } }; class SongPlayer; struct SampleBuffer { Sample_t volatile buf[ SAMPLES_PER_BUFFER ]; size_t volatile samplesRemaining; Sample_t volatile * volatile nextSample; bool isDone() { return !samplesRemaining; } float remainingDuration() { return samplesRemaining / SAMPLE_RATE_HZ; } // return true if we read any samples bool loadFrom(FILE *fp) { samplesRemaining = fread((void *)buf, sizeof(Sample_t), SAMPLES_PER_BUFFER, fp); nextSample = buf; return samplesRemaining > 0; } SampleBuffer() : samplesRemaining(0), nextSample(buf) { } }; struct SongPlayer { SampleBuffer * volatile playing; SampleBuffer * volatile loading; SampleBuffer buffer[2]; FILE *fp; size_t nChunks; size_t volatile chunksRemaining; bool startSong(char const *name) { if (fp) fclose(fp); fp = fopen(name, "rb"); if (!fp) return false; if (fseek(fp, 0, SEEK_END)) return false; long fileSize = ftell(fp); if (fileSize < 0) return false; if (fseek(fp, 0, SEEK_SET)) return false; chunksRemaining = nChunks = fileSize / BUFFER_SIZE; loading = &buffer[0]; playing = &buffer[1]; return loadNextChunk(); } // swap loading/playing buffers; // decrement chunksRemaining void swapBuffers() { SampleBuffer * volatile tmp = playing; if (tmp == buffer + 0) playing = buffer + 1; else playing = buffer + 0; loading = tmp; if (chunksRemaining) chunksRemaining--; } // get next chunk of file into *loading // to prepare for eventual swap. // returns true if more samples remain bool loadNextChunk() { if (! chunksRemaining) return false; bool notDone = loading->loadFrom(fp); return notDone; } bool isDone() { return !chunksRemaining; } }; std::list<Song> songs; int main() { // read the directory DIR *bassDir = opendir(BASS_DIRECTORY); if (bassDir) { while (dirent *dir = bassDir->readdir()) { pc.printf("%s", dir->d_name); // if this is a valid wave filename if (Song::isValidWaveFileName(dir->d_name)) { pc.printf("\tvalid\r\n"); } else { pc.printf("\tnot valid\r\n"); } } } else { pc.printf("Error opening " BASS_DIRECTORY); } for(;;) ; }