Big Mouth Billy Bass automation library
Revision 4:f009306756b3, committed 2013-06-18
- 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
--- 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