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

Dependencies:   SDFileSystem mbed BillyBass

Files at this revision

API Documentation at this revision

Comitter:
bikeNomad
Date:
Mon Jun 17 22:18:12 2013 +0000
Parent:
6:e90a12ca056f
Child:
8:1dd2bb31dec6
Commit message:
mostly working; hangs when reading actions

Changed in this revision

BillyBass.lib Show annotated file Show diff for this revision Revisions of this file
action.hpp Show diff for this revision Revisions of this file
billybass.hpp Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
player.hpp Show diff for this revision Revisions of this file
song.hpp Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BillyBass.lib	Mon Jun 17 22:18:12 2013 +0000
@@ -0,0 +1,1 @@
+BillyBass#84aaade0de8f
--- a/action.hpp	Sat Jun 15 04:08:25 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-#ifndef __included_action_hpp
-#define __included_action_hpp
-
-#include "billybass.hpp"
-
-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;
-    }
-};
-
-#endif
--- a/billybass.hpp	Sat Jun 15 04:08:25 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-#ifndef __included_billybass_hpp
-#define __included_billybass_hpp
-
-#include "mbed.h"
-#include "SDFileSystem.h"
-#include <list>
-#include <cmath>
-
-struct Song;
-
-#define SD_NAME "sd"
-#define SD_ROOT "/" SD_NAME
-#define BASS_DIRECTORY SD_ROOT "/SD_Files"
-
-typedef int16_t Sample_t;   // 16-bit raw, LE samples
-
-const size_t BUFFER_SIZE = 512;
-const float SAMPLE_RATE_HZ = 8000.0;
-#define MAX_BASENAME_LENGTH 30
-#define MAX_FILENAME_LENGTH 60
-#define MAX_ACTION_LINE_LENGTH 100
-#define SERIAL_BAUD 115200
-
-const unsigned SAMPLE_PERIOD_USEC = (unsigned)(1.0e6/SAMPLE_RATE_HZ);
-const size_t SAMPLES_PER_BUFFER = BUFFER_SIZE / sizeof(Sample_t);
-const float SECONDS_PER_CHUNK = SAMPLES_PER_BUFFER / SAMPLE_RATE_HZ;
-
-extern DigitalOut tail;     // J3/2
-extern DigitalOut mouth;    // J3/1
-extern DigitalOut head;     // J3/3
-extern DigitalIn pushbutton; // J3/4
-extern PwmOut redLED;
-extern PwmOut greenLED;
-extern PwmOut blueLED;
-extern AnalogOut speaker;   // J10/11
-extern SDFileSystem sd;
-extern Serial pc;
-extern std::list<Song> songs;
-
-#endif
--- a/main.cpp	Sat Jun 15 04:08:25 2013 +0000
+++ b/main.cpp	Mon Jun 17 22:18:12 2013 +0000
@@ -1,4 +1,5 @@
 #include "billybass.hpp"
+#include "SDFileSystem.h"
 #include "song.hpp"
 #include "player.hpp"
 #include "action.hpp"
@@ -7,17 +8,15 @@
 // Power GND  J9/14
 // Vin (6V)   J9/16
 
-// Digital:
-DigitalOut tail(PTA13);                // J3/2
-DigitalOut mouth(PTC12);               // J3/1
-DigitalOut head(PTC13);                // J3/3
+//                 tailPin,  mouthPin, bodyPin
+BillyBass testBass(LED_RED, LED_GREEN, LED_BLUE);
+
+//               tailPin, mouthPin, bodyPin
+//                  J3/2,  J3/1, J3/3
+BillyBass realBass(PTA13, PTC12, PTC13);
 
 DigitalIn pushbutton(PTD5); // J3/4
 
-PwmOut redLED(LED_RED);
-PwmOut greenLED(LED_GREEN);
-PwmOut blueLED(LED_BLUE);
-
 // Analog:
 // GND   J3/14
 // VrefH J3/16
@@ -28,44 +27,33 @@
 // PTD3 D12 - Used for MISO of SPI
 // PTC5 J1/9  Used for SCLK of SPI
 
-//              MOSI, MISO, SCLK, CS, name
+//              MOSI, MISO, SCLK,   CS, name
 SDFileSystem sd(PTD2, PTD3, PTC5, PTD0, SD_NAME);
+
 Serial pc(USBTX, USBRX);
 
-std::list<Song> songs;
-
 int main()
 {
     SongPlayer player;
     pc.baud(SERIAL_BAUD);
-    redLED = 1.0;
-    greenLED = 1.0;
-    blueLED = 1.0;
+
+    pc.printf("*** REBOOT ***\r\n");
 
     // read the directory
-    DIR *bassDir = opendir(BASS_DIRECTORY);
-    if (bassDir)
-    {
-        while (dirent *dir = bassDir->readdir())
-        {
-            char fn[ MAX_FILENAME_LENGTH ];
-            snprintf(fn, sizeof(fn), "%s/%s", BASS_DIRECTORY, dir->d_name);
-            pc.printf(fn);
-            // if this is a valid wave filename
-            if (Song::isValidWaveFileName(fn))
-            {
-                pc.printf("\tvalid\r\n");
-                player.playEntireSong(fn);
-                pc.printf("Song time: %f\r\n", player.timeInSong);
-            }
-            else
-            {
-                pc.printf("\tnot valid\r\n");
-            }
+    DIR *bassDir = 0;
+    while (!bassDir) {
+        if ((bassDir = opendir(BASS_DIRECTORY)) != 0)
+            break;
+        pc.printf("Error opening " BASS_DIRECTORY "\r\n");
+        wait(1.0);
+    }
+
+    if (!Song::readAllSongs(bassDir)) {
+        pc.printf("Found no songs!\r\n");
+    } else {
+        for (std::list<Song *>::const_iterator song_it = Song::songs.begin(); song_it != Song::songs.end(); song_it++) {
+            Song *song = *song_it;
+            song->print(pc);
         }
     }
-    else
-    {
-        pc.printf("Error opening " BASS_DIRECTORY);
-    }
 }
--- a/player.hpp	Sat Jun 15 04:08:25 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-#ifndef __included_player_hpp
-#define __included_player_hpp
-
-#include "billybass.hpp"
-
-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;
-    }
-
-    Sample_t getNextSample()
-    {
-        --samplesRemaining;
-        return *++nextSample;
-    }
-
-    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;
-    float timeInSong;
-    Ticker sampleTicker;
-
-    SongPlayer() : playing(0)
-        , loading(0)
-        , fp(0)
-        , nChunks(0)
-        , chunksRemaining(0)
-    {
-    }
-
-    // interrupt handler
-    void playNextSample(void)
-    {
-        if (playing->samplesRemaining == 0)
-            swapBuffers();
-        // NOTE bias of 0xC000 requires normalizing to 75% of full scale
-        speaker.write_u16(static_cast<uint16_t>(playing->getNextSample() + 0x8000) / 2);
-    }
-
-    bool startSong(char const *name)
-    {
-        pc.printf("starting %s: ", name);
-        if (fp) fclose(fp);
-        fp = fopen(name, "rb");
-        pc.printf("opened, ");
-        if (!fp) return false;
-
-        pc.printf("seekend, ");
-        if (fseek(fp, 0, SEEK_END)) return false;
-
-        long fileSize = ftell(fp);
-        pc.printf("size=%d, ", fileSize);
-        if (fileSize < 0) return false;
-
-        if (fseek(fp, 0, SEEK_SET)) return false;
-
-        pc.printf("rewound, ");
-        chunksRemaining = nChunks = fileSize / BUFFER_SIZE;
-        loading         = &buffer[0];
-        playing         = &buffer[1];
-        pc.printf("chunks=%d expected=%f seconds\r\n", nChunks, nChunks * SECONDS_PER_CHUNK);
-        if (!loadNextChunk())
-            return false;
-
-        timeInSong = 0.0;
-        sampleTicker.attach_us(this, &SongPlayer::playNextSample, SAMPLE_PERIOD_USEC);
-        return true;
-    }
-
-    // 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;
-    }
-
-    // look at loading buffer; load only if necessary.
-    bool loadIfNecessary()
-    {
-        if (loading->isDone())
-        {
-            timeInSong += SECONDS_PER_CHUNK;
-            return loadNextChunk();
-        }
-        else { return true; }
-    }
-
-    void playEntireSong(char const *name)
-    {
-        if (!startSong(name)) return;
-
-        while (!isDone())
-        {
-            loadIfNecessary();
-        }
-        sampleTicker.detach();
-    }
-};
-
-#endif
--- a/song.hpp	Sat Jun 15 04:08:25 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-#ifndef __included_song_hpp
-#define __included_song_hpp
-
-#include "billybass.hpp"
-#include "action.hpp"
-
-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, BASS_DIRECTORY "/%u_%u_%s", &num1, &num2, basename);
-        if (nItems != 3)
-        {
-            return false;
-        }
-        char *p = strrchr(basename, '.');
-        if (!p)
-        {
-            return false;
-        }
-        strcpy(extension, p+1);
-        *p = 0;
-        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);
-    }
-};
-
-#endif                                 // __included_song_hpp