Big Mouth Billy Bass automation library

Dependents:   BillyBass_with_SD

Files at this revision

API Documentation at this revision

Comitter:
bikeNomad
Date:
Tue Jun 18 14:10:34 2013 +0000
Parent:
3:6c91a6232c4a
Child:
5:869b3711bdb3
Commit message:
working. re-used one Song for memory reduction.

Changed in this revision

action.hpp Show annotated file Show diff for this revision Revisions of this file
billybass.cpp Show annotated file Show diff for this revision Revisions of this file
billybass.hpp Show annotated file Show diff for this revision Revisions of this file
player.hpp Show annotated file Show diff for this revision Revisions of this file
song.cpp Show annotated file Show diff for this revision Revisions of this file
song.hpp Show annotated file Show diff for this revision Revisions of this file
--- a/action.hpp	Tue Jun 18 13:11:07 2013 +0000
+++ b/action.hpp	Tue Jun 18 14:10:34 2013 +0000
@@ -15,12 +15,17 @@
            DigitalOut *_out = 0,
            char const *_outName = 0)
         : actionTime(_time), desiredState(_state)
-        , output(_out), outputName(_outName) {
+        , output(_out) {
     }
 
     bool operator < (Action const &other) const {
         return actionTime < other.actionTime;
     }
+    
+    // return <0 if *p1 is before *p2
+    static int compare(const void* p1, const void* p2) {
+        return static_cast<Action const *>(p1)->actionTime - static_cast<Action const *>(p2)->actionTime;
+    }
 
     bool isValid() const {
         return actionTime >= 0.0 && output != 0;
@@ -29,18 +34,22 @@
     void act() {
         output->write(desiredState ? 1 : 0);
     }
-    
+
     bool actIfPast(float _now) {
         if (_now >= actionTime) {
             act();
             return true;
         } else return false;
     }
+    void set(float _time, int _state, DigitalOut* _out) {
+        actionTime = _time;
+        desiredState = _state;
+        output = _out;
+    }
 
     float actionTime;
-    bool desiredState;
+    int desiredState;
     DigitalOut *output;
-    char const *outputName;
 };
 
 #endif
--- a/billybass.cpp	Tue Jun 18 13:11:07 2013 +0000
+++ b/billybass.cpp	Tue Jun 18 14:10:34 2013 +0000
@@ -16,15 +16,21 @@
     if (!strcmp(_outputName, mouthName)) {
         output = &mouth;
         if (_pName) *_pName = mouthName;
-    }
-    else if (!strcmp(_outputName, "head") || !strcmp(_outputName, bodyName)) {
+    } else if (!strcmp(_outputName, "head") || !strcmp(_outputName, bodyName)) {
         output = &body;
         if (_pName) *_pName = bodyName;
-    }
-    else if (!strcmp(_outputName, tailName)) {
+    } else if (!strcmp(_outputName, tailName)) {
         output = &tail;
         if (_pName) *_pName = tailName;
     }
 
     return output;
 }
+
+char const *BillyBass::outputName(DigitalOut const *out) const
+{
+    if (out == &tail) return tailName;
+    else if (out == &body) return bodyName;
+    else if (out == &mouth) return mouthName;
+    else return "unknown";
+}
--- a/billybass.hpp	Tue Jun 18 13:11:07 2013 +0000
+++ b/billybass.hpp	Tue Jun 18 14:10:34 2013 +0000
@@ -42,6 +42,7 @@
         mouth.write(offState());
         body.write(offState());
     }
+    char const * outputName(DigitalOut const *out) const;
 
 protected:
     static BillyBass* fish[ MAX_FISH ];
--- a/player.hpp	Tue Jun 18 13:11:07 2013 +0000
+++ b/player.hpp	Tue Jun 18 14:10:34 2013 +0000
@@ -47,7 +47,7 @@
     float timeInSong;
     Ticker sampleTicker;
     Song *song;
-    Song::actions_t::iterator nextAction;
+    Action *nextAction;
     unsigned actionsDone;
 
     SongPlayer() : playing(0)
@@ -68,26 +68,25 @@
     }
 
     bool startSong(Song *_song) {
-        if (song) delete song;
         song = _song;
-        nextAction = song->getActions().begin();
+        nextAction = song->getActions();
         timeInSong = 0.0;
         actionsDone = 0;
 
         fprintf(stderr, "starting %s: ", song->getSampleFileName());
         if (fp) fclose(fp);
         fp = fopen(song->getSampleFileName(), "rb");
+        if (!fp) goto on_error;
         fprintf(stderr, "opened, ");
-        if (!fp) return false;
 
+        if (fseek(fp, 0, SEEK_END)) goto on_error;
         fprintf(stderr, "seekend, ");
-        if (fseek(fp, 0, SEEK_END)) return false;
 
         long fileSize = ftell(fp);
         fprintf(stderr, "size=%d, ", fileSize);
-        if (fileSize < 0) return false;
+        if (fileSize < 0) goto on_error;
 
-        if (fseek(fp, 0, SEEK_SET)) return false;
+        if (fseek(fp, 0, SEEK_SET)) goto on_error;
 
         fprintf(stderr, "rewound, ");
         chunksRemaining = nChunks = fileSize / BUFFER_SIZE;
@@ -96,11 +95,16 @@
         fprintf(stderr, "chunks=%d expected=%f seconds\r\n", nChunks, nChunks * SECONDS_PER_CHUNK);
         if (!loadNextChunk()) {
             fprintf(stderr, "first chunk empty!\r\n");
-            return false;
+            goto on_error;
         }
 
         sampleTicker.attach_us(this, &SongPlayer::playNextSample, SAMPLE_PERIOD_USEC);
         return true;
+
+on_error:
+        if (fp) fclose(fp);
+        fp = 0;
+        return false;
     }
 
     // swap loading/playing buffers;
@@ -133,7 +137,7 @@
     // look at loading buffer; load only if necessary.
     bool loadIfNecessary() {
         if (loading->isDone()) {
-        fprintf(stderr, "*");
+            fprintf(stderr, "*");
             timeInSong += SECONDS_PER_CHUNK;
             return loadNextChunk();
         } else {
@@ -143,10 +147,10 @@
 
     void playEntireSong(Song *_song) {
         if (!startSong(_song)) return;
-
+        Action* lastAction = song->getActions() + song->getNumActions();
         while (!isDone()) {
-            while (nextAction != song->getActions().end() && nextAction->actIfPast(timeInSong)) {
-            fprintf(stderr, ".");
+            while (nextAction < lastAction && nextAction->actIfPast(timeInSong)) {
+                fprintf(stderr, ".");
                 actionsDone++;
                 nextAction++;
             }
--- a/song.cpp	Tue Jun 18 13:11:07 2013 +0000
+++ b/song.cpp	Tue Jun 18 14:10:34 2013 +0000
@@ -15,16 +15,15 @@
 char const *Song::sampleExtension = "raw";
 // class static
 unsigned const Song::NO_FISH = MAX_FISH + 1;
+// one song, re-used
+Song Song::theSong;
 
 // _name is relative to BASS_DIRECTORY
 // class static
 Song *Song::newSong(char const *_name)
 {
-    Song *s = new Song;
-    if (!s) {
-        fprintf(stderr, "new Song == 0\r\n");
-        return 0;
-    }
+    Song *s = &theSong;
+    s->reset();
     if (! s->parseFilename(_name)) {
         fprintf(stderr, "parseFilename(%s) failed\r\n", _name);
         goto on_error;
@@ -38,7 +37,6 @@
     return s;
 
 on_error:
-    delete s;
     return 0;
 }
 
@@ -131,11 +129,11 @@
         }
         // fprintf(stderr, "%d add %f %f %s\r\n", line, startTime, endTime, outName);
 
-        actions.push_back(Action(startTime, bass->onState(), out, outName));
-        actions.push_back(Action(endTime, bass->offState(), out, outName));
+        addAction(startTime, bass->onState(), out);
+        addAction(endTime, bass->offState(), out);
     }
-    fprintf(stderr, "Added %d actions\r\n", actions.size());
-    std::sort(actions.begin(), actions.end()); // sort actions by time
+    fprintf(stderr, "Added %d actions\r\n", numActions);
+    qsort(actions, numActions, sizeof(Action), &Action::compare);
     retval = true;
 
 done:
@@ -143,3 +141,4 @@
     fclose(txtfile);
     return retval;
 }
+
--- a/song.hpp	Tue Jun 18 13:11:07 2013 +0000
+++ b/song.hpp	Tue Jun 18 14:10:34 2013 +0000
@@ -10,22 +10,24 @@
 class Song
 {
 public:
-    typedef std::vector<Action> actions_t;
+    typedef Action actions_t[ MAX_ACTIONS_PER_SONG ];
 
     // _name is relative to BASS_DIRECTORY
     // return a pointer to a fully read-in Song if valid
-    // also adds new song to songs
     static Song *newSong(char const *_name);
 
-    Song() : sequenceNumber(0), whichFish(NO_FISH), basename(0), extension(0) {
-        fullname[0] = 0;
-        actions.reserve(MAX_ACTIONS_PER_SONG);
+
+    void reset() {
+        sequenceNumber = 0;
+        whichFish = NO_FISH;
+        basename = 0;
+        extension = 0;
+        numActions = 0;
     }
-    ~Song() {
-        actions.clear();
+
+    BillyBass * myFish() {
+        return BillyBass::bassNumber(whichFish);
     }
-    
-    BillyBass * myFish() { return BillyBass::bassNumber(whichFish); }
     bool isValid() const {
         return basename != 0 && whichFish != NO_FISH;
     }
@@ -48,24 +50,37 @@
         strcpy(extension, textExtension);
         return fullname;
     }
-    actions_t &getActions() {
+    Action *getActions() {
         return actions;
     }
+    bool addAction(float _time, int _state, DigitalOut* _out) {
+        if (numActions >= MAX_ACTIONS_PER_SONG) return false;
+        actions[numActions++].set(_time, _state, _out);
+        return true;
+    }
+    unsigned getNumActions() const {
+        return numActions;
+    }
 
     void print(FILE *f) {
         fprintf(f, "%s fish=%u seq=%u\r\n", getSampleFileName(), whichFish, sequenceNumber);
-        for (actions_t::const_iterator action_it = actions.begin(); action_it != actions.end(); action_it++) {
-            Action const &action = *action_it;
-            fprintf(f, "%0.02f %s %d\r\n", action.actionTime, action.outputName, action.desiredState ? 1 : 0);
+        Action *lastAction = actions + numActions;
+        for (Action *action = actions; action < lastAction; action++) {
+            fprintf(f, "%0.02f %s %d\r\n", action->actionTime, myFish()->outputName(action->output), action->desiredState);
         }
     }
 
 protected:
+    Song() {
+        reset();
+    }
+    ~Song() {}
 
     static char const directoryName[ BASS_DIRECTORY_LENGTH + 1 ];
     static unsigned const NO_FISH;
     static char const *textExtension;
     static char const *sampleExtension;
+    static Song theSong;
 
     unsigned sequenceNumber;    // 0-relative
     unsigned whichFish;         // 0-relative
@@ -73,6 +88,7 @@
     char *basename;     // points into fullname
     char *extension;    // points into fullname
     actions_t actions;
+    unsigned numActions;
 };
 
 #endif                                 // __included_song_hpp