Big Mouth Billy Bass player that takes raw wavefiles and decision list text files from an SD card

Dependencies:   SDFileSystem mbed BillyBass

Committer:
bikeNomad
Date:
Wed Jun 05 15:33:45 2013 +0000
Revision:
0:0944c3654ded
Child:
1:f3f439154ab4
first attempt; still incomplete

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bikeNomad 0:0944c3654ded 1 #include "mbed.h"
bikeNomad 0:0944c3654ded 2 #include "SDFileSystem.h"
bikeNomad 0:0944c3654ded 3 #include <list>
bikeNomad 0:0944c3654ded 4 #include <cmath>
bikeNomad 0:0944c3654ded 5
bikeNomad 0:0944c3654ded 6 #define SD_NAME "sd"
bikeNomad 0:0944c3654ded 7 #define SD_ROOT "/" SD_NAME
bikeNomad 0:0944c3654ded 8 #define BASS_DIRECTORY SD_ROOT
bikeNomad 0:0944c3654ded 9
bikeNomad 0:0944c3654ded 10 // Power:
bikeNomad 0:0944c3654ded 11 // Power GND J9/14
bikeNomad 0:0944c3654ded 12 // Vin (6V) J9/16
bikeNomad 0:0944c3654ded 13
bikeNomad 0:0944c3654ded 14 // Digital:
bikeNomad 0:0944c3654ded 15 DigitalOut tail(PTA13); // J3/2
bikeNomad 0:0944c3654ded 16 DigitalOut mouth(PTC12); // J3/1
bikeNomad 0:0944c3654ded 17 DigitalOut head(PTC13); // J3/3
bikeNomad 0:0944c3654ded 18
bikeNomad 0:0944c3654ded 19 DigitalIn pushbutton(PTD5); // J3/4
bikeNomad 0:0944c3654ded 20
bikeNomad 0:0944c3654ded 21 PwmOut redLED(LED_RED);
bikeNomad 0:0944c3654ded 22 PwmOut greenLED(LED_GREEN);
bikeNomad 0:0944c3654ded 23 PwmOut blueLED(LED_BLUE);
bikeNomad 0:0944c3654ded 24
bikeNomad 0:0944c3654ded 25 // Analog:
bikeNomad 0:0944c3654ded 26 // GND J3/14
bikeNomad 0:0944c3654ded 27 // VrefH J3/16
bikeNomad 0:0944c3654ded 28 AnalogOut speaker(PTE30); // J10/11
bikeNomad 0:0944c3654ded 29
bikeNomad 0:0944c3654ded 30 // PTD0 D10 – Used for CS of SPI
bikeNomad 0:0944c3654ded 31 // PTD2 D11 – Used for MOSI of SPI
bikeNomad 0:0944c3654ded 32 // PTD3 D12 – Used for MISO of SPI
bikeNomad 0:0944c3654ded 33 // PTC5 J1/9 Used for SCLK of SPI
bikeNomad 0:0944c3654ded 34
bikeNomad 0:0944c3654ded 35 // MOSI, MISO, SCLK, CS, name
bikeNomad 0:0944c3654ded 36 SDFileSystem sd(PTD2, PTD3, PTC5, PTD0, SD_NAME);
bikeNomad 0:0944c3654ded 37 Serial pc(USBTX, USBRX);
bikeNomad 0:0944c3654ded 38
bikeNomad 0:0944c3654ded 39 typedef int16_t Sample_t; // 16-bit raw, LE samples
bikeNomad 0:0944c3654ded 40
bikeNomad 0:0944c3654ded 41 const size_t BUFFER_SIZE = 512;
bikeNomad 0:0944c3654ded 42 const float SAMPLE_RATE_HZ = 8000.0;
bikeNomad 0:0944c3654ded 43 const size_t SAMPLES_PER_BUFFER = BUFFER_SIZE / sizeof(Sample_t);
bikeNomad 0:0944c3654ded 44 const float SECONDS_PER_CHUNK = SAMPLES_PER_BUFFER / SAMPLE_RATE_HZ;
bikeNomad 0:0944c3654ded 45
bikeNomad 0:0944c3654ded 46 struct Action {
bikeNomad 0:0944c3654ded 47 float actionTime;
bikeNomad 0:0944c3654ded 48 bool desiredState;
bikeNomad 0:0944c3654ded 49 DigitalOut *output;
bikeNomad 0:0944c3654ded 50
bikeNomad 0:0944c3654ded 51 bool operator < (Action const &other) const {
bikeNomad 0:0944c3654ded 52 return actionTime < other.actionTime;
bikeNomad 0:0944c3654ded 53 }
bikeNomad 0:0944c3654ded 54
bikeNomad 0:0944c3654ded 55 bool isValid() {
bikeNomad 0:0944c3654ded 56 return actionTime >= 0.0 && output != 0;
bikeNomad 0:0944c3654ded 57 }
bikeNomad 0:0944c3654ded 58
bikeNomad 0:0944c3654ded 59 Action() : actionTime(-1.0), desiredState(false), output(0) {
bikeNomad 0:0944c3654ded 60 }
bikeNomad 0:0944c3654ded 61
bikeNomad 0:0944c3654ded 62 bool parseLine(char const *line) {
bikeNomad 0:0944c3654ded 63 // TODO
bikeNomad 0:0944c3654ded 64 return true;
bikeNomad 0:0944c3654ded 65 }
bikeNomad 0:0944c3654ded 66 };
bikeNomad 0:0944c3654ded 67
bikeNomad 0:0944c3654ded 68 #define MAX_BASENAME_LENGTH 30
bikeNomad 0:0944c3654ded 69 #define MAX_ACTION_LINE_LENGTH 100
bikeNomad 0:0944c3654ded 70
bikeNomad 0:0944c3654ded 71 struct Song {
bikeNomad 0:0944c3654ded 72 char basename[ MAX_BASENAME_LENGTH + 1 ];
bikeNomad 0:0944c3654ded 73 unsigned sequenceNumber;
bikeNomad 0:0944c3654ded 74 unsigned whichFish;
bikeNomad 0:0944c3654ded 75 std::list<Action> actions;
bikeNomad 0:0944c3654ded 76
bikeNomad 0:0944c3654ded 77 Song() : sequenceNumber(0), whichFish(3) {
bikeNomad 0:0944c3654ded 78 basename[0] = 0;
bikeNomad 0:0944c3654ded 79 }
bikeNomad 0:0944c3654ded 80
bikeNomad 0:0944c3654ded 81 bool readWaveFile(char const *_waveFileName) {
bikeNomad 0:0944c3654ded 82 if (!parseFilename(_waveFileName, sequenceNumber, whichFish, basename)) return false;
bikeNomad 0:0944c3654ded 83 char txtFileName[ FILENAME_MAX ];
bikeNomad 0:0944c3654ded 84 sprintf(txtFileName, "%u_%u_%s.txt", sequenceNumber, whichFish, basename);
bikeNomad 0:0944c3654ded 85 FILE *txtfile = fopen(txtFileName, "rt");
bikeNomad 0:0944c3654ded 86 if (!txtfile) return false; // TODO
bikeNomad 0:0944c3654ded 87 // read actions from file
bikeNomad 0:0944c3654ded 88 char actionLine[ MAX_ACTION_LINE_LENGTH + 1 ];
bikeNomad 0:0944c3654ded 89 while (fgets(actionLine, sizeof(actionLine), txtfile)) {
bikeNomad 0:0944c3654ded 90 Action action;
bikeNomad 0:0944c3654ded 91 if (action.parseLine(actionLine)) {
bikeNomad 0:0944c3654ded 92 actions.push_back(action);
bikeNomad 0:0944c3654ded 93 }
bikeNomad 0:0944c3654ded 94 }
bikeNomad 0:0944c3654ded 95 return true;
bikeNomad 0:0944c3654ded 96 }
bikeNomad 0:0944c3654ded 97
bikeNomad 0:0944c3654ded 98 static bool parseFilename(char const *_name, unsigned &_num1, unsigned &_num2, char *_basename) {
bikeNomad 0:0944c3654ded 99 char basename[ MAX_BASENAME_LENGTH + 1 ];
bikeNomad 0:0944c3654ded 100 unsigned num1, num2;
bikeNomad 0:0944c3654ded 101 char extension[ 4 ];
bikeNomad 0:0944c3654ded 102 int nItems = sscanf(_name, "%u_%u_%30[^_.].%3[a-zA-Z]", &num1, &num2, basename, extension);
bikeNomad 0:0944c3654ded 103 if (nItems != 4) return false;
bikeNomad 0:0944c3654ded 104 if (num2 > 2) return false;
bikeNomad 0:0944c3654ded 105 if (strcasecmp("raw", extension)) return false;
bikeNomad 0:0944c3654ded 106 _num1 = num1;
bikeNomad 0:0944c3654ded 107 _num2 = num2;
bikeNomad 0:0944c3654ded 108 strcpy(_basename, basename);
bikeNomad 0:0944c3654ded 109 return true;
bikeNomad 0:0944c3654ded 110 }
bikeNomad 0:0944c3654ded 111
bikeNomad 0:0944c3654ded 112 // return true if filename is of proper format
bikeNomad 0:0944c3654ded 113 // <num>_<num>_<name>.raw
bikeNomad 0:0944c3654ded 114 // and there is a corresponding .txt file
bikeNomad 0:0944c3654ded 115 static bool isValidWaveFileName(char const *_name) {
bikeNomad 0:0944c3654ded 116 unsigned int num1, num2;
bikeNomad 0:0944c3654ded 117 char basename[ 31 ];
bikeNomad 0:0944c3654ded 118 return parseFilename(_name, num1, num2, basename);
bikeNomad 0:0944c3654ded 119 }
bikeNomad 0:0944c3654ded 120 };
bikeNomad 0:0944c3654ded 121
bikeNomad 0:0944c3654ded 122 class SongPlayer;
bikeNomad 0:0944c3654ded 123
bikeNomad 0:0944c3654ded 124 struct SampleBuffer {
bikeNomad 0:0944c3654ded 125 Sample_t volatile buf[ SAMPLES_PER_BUFFER ];
bikeNomad 0:0944c3654ded 126 size_t volatile samplesRemaining;
bikeNomad 0:0944c3654ded 127 Sample_t volatile * volatile nextSample;
bikeNomad 0:0944c3654ded 128
bikeNomad 0:0944c3654ded 129 bool isDone() {
bikeNomad 0:0944c3654ded 130 return !samplesRemaining;
bikeNomad 0:0944c3654ded 131 }
bikeNomad 0:0944c3654ded 132
bikeNomad 0:0944c3654ded 133 float remainingDuration() {
bikeNomad 0:0944c3654ded 134 return samplesRemaining / SAMPLE_RATE_HZ;
bikeNomad 0:0944c3654ded 135 }
bikeNomad 0:0944c3654ded 136
bikeNomad 0:0944c3654ded 137 // return true if we read any samples
bikeNomad 0:0944c3654ded 138 bool loadFrom(FILE *fp) {
bikeNomad 0:0944c3654ded 139 samplesRemaining = fread((void *)buf, sizeof(Sample_t), SAMPLES_PER_BUFFER, fp);
bikeNomad 0:0944c3654ded 140 nextSample = buf;
bikeNomad 0:0944c3654ded 141 return samplesRemaining > 0;
bikeNomad 0:0944c3654ded 142 }
bikeNomad 0:0944c3654ded 143
bikeNomad 0:0944c3654ded 144 SampleBuffer() : samplesRemaining(0), nextSample(buf) { }
bikeNomad 0:0944c3654ded 145 };
bikeNomad 0:0944c3654ded 146
bikeNomad 0:0944c3654ded 147 struct SongPlayer {
bikeNomad 0:0944c3654ded 148 SampleBuffer * volatile playing;
bikeNomad 0:0944c3654ded 149 SampleBuffer * volatile loading;
bikeNomad 0:0944c3654ded 150 SampleBuffer buffer[2];
bikeNomad 0:0944c3654ded 151 FILE *fp;
bikeNomad 0:0944c3654ded 152 size_t nChunks;
bikeNomad 0:0944c3654ded 153 size_t volatile chunksRemaining;
bikeNomad 0:0944c3654ded 154
bikeNomad 0:0944c3654ded 155 bool startSong(char const *name) {
bikeNomad 0:0944c3654ded 156 if (fp) fclose(fp);
bikeNomad 0:0944c3654ded 157 fp = fopen(name, "rb");
bikeNomad 0:0944c3654ded 158 if (!fp) return false;
bikeNomad 0:0944c3654ded 159 if (fseek(fp, 0, SEEK_END)) return false;
bikeNomad 0:0944c3654ded 160 long fileSize = ftell(fp);
bikeNomad 0:0944c3654ded 161 if (fileSize < 0) return false;
bikeNomad 0:0944c3654ded 162 if (fseek(fp, 0, SEEK_SET)) return false;
bikeNomad 0:0944c3654ded 163 chunksRemaining = nChunks = fileSize / BUFFER_SIZE;
bikeNomad 0:0944c3654ded 164 loading = &buffer[0];
bikeNomad 0:0944c3654ded 165 playing = &buffer[1];
bikeNomad 0:0944c3654ded 166 return loadNextChunk();
bikeNomad 0:0944c3654ded 167 }
bikeNomad 0:0944c3654ded 168
bikeNomad 0:0944c3654ded 169 // swap loading/playing buffers;
bikeNomad 0:0944c3654ded 170 // decrement chunksRemaining
bikeNomad 0:0944c3654ded 171 void swapBuffers() {
bikeNomad 0:0944c3654ded 172 SampleBuffer * volatile tmp = playing;
bikeNomad 0:0944c3654ded 173 if (tmp == buffer + 0)
bikeNomad 0:0944c3654ded 174 playing = buffer + 1;
bikeNomad 0:0944c3654ded 175 else
bikeNomad 0:0944c3654ded 176 playing = buffer + 0;
bikeNomad 0:0944c3654ded 177 loading = tmp;
bikeNomad 0:0944c3654ded 178 if (chunksRemaining)
bikeNomad 0:0944c3654ded 179 chunksRemaining--;
bikeNomad 0:0944c3654ded 180 }
bikeNomad 0:0944c3654ded 181
bikeNomad 0:0944c3654ded 182 // get next chunk of file into *loading
bikeNomad 0:0944c3654ded 183 // to prepare for eventual swap.
bikeNomad 0:0944c3654ded 184 // returns true if more samples remain
bikeNomad 0:0944c3654ded 185 bool loadNextChunk() {
bikeNomad 0:0944c3654ded 186 if (! chunksRemaining) return false;
bikeNomad 0:0944c3654ded 187 bool notDone = loading->loadFrom(fp);
bikeNomad 0:0944c3654ded 188 return notDone;
bikeNomad 0:0944c3654ded 189 }
bikeNomad 0:0944c3654ded 190
bikeNomad 0:0944c3654ded 191 bool isDone() {
bikeNomad 0:0944c3654ded 192 return !chunksRemaining;
bikeNomad 0:0944c3654ded 193 }
bikeNomad 0:0944c3654ded 194
bikeNomad 0:0944c3654ded 195 };
bikeNomad 0:0944c3654ded 196
bikeNomad 0:0944c3654ded 197 std::list<Song> songs;
bikeNomad 0:0944c3654ded 198
bikeNomad 0:0944c3654ded 199 int main()
bikeNomad 0:0944c3654ded 200 {
bikeNomad 0:0944c3654ded 201 // read the directory
bikeNomad 0:0944c3654ded 202 DIR *bassDir = opendir(BASS_DIRECTORY);
bikeNomad 0:0944c3654ded 203 if (bassDir) {
bikeNomad 0:0944c3654ded 204 while (dirent *dir = bassDir->readdir()) {
bikeNomad 0:0944c3654ded 205 pc.printf("%s", dir->d_name);
bikeNomad 0:0944c3654ded 206 // if this is a valid wave filename
bikeNomad 0:0944c3654ded 207 if (Song::isValidWaveFileName(dir->d_name)) {
bikeNomad 0:0944c3654ded 208 pc.printf("\tvalid\r\n");
bikeNomad 0:0944c3654ded 209 } else {
bikeNomad 0:0944c3654ded 210 pc.printf("\tnot valid\r\n");
bikeNomad 0:0944c3654ded 211 }
bikeNomad 0:0944c3654ded 212 }
bikeNomad 0:0944c3654ded 213 } else {
bikeNomad 0:0944c3654ded 214 pc.printf("Error opening " BASS_DIRECTORY);
bikeNomad 0:0944c3654ded 215 }
bikeNomad 0:0944c3654ded 216
bikeNomad 0:0944c3654ded 217 for(;;)
bikeNomad 0:0944c3654ded 218 ;
bikeNomad 0:0944c3654ded 219 }