Big Mouth Billy Bass automation library
Diff: player.hpp
- Revision:
- 2:eaba75af0f0d
- Parent:
- 0:84aaade0de8f
- Child:
- 3:6c91a6232c4a
--- a/player.hpp Tue Jun 18 00:07:47 2013 +0000 +++ b/player.hpp Tue Jun 18 06:12:48 2013 +0000 @@ -5,32 +5,27 @@ class SongPlayer; -struct SampleBuffer -{ +struct SampleBuffer { Sample_t volatile buf[ SAMPLES_PER_BUFFER ]; size_t volatile samplesRemaining; Sample_t volatile * volatile nextSample; - bool isDone() - { + bool isDone() { return !samplesRemaining; } - float remainingDuration() - { + float remainingDuration() { return samplesRemaining / SAMPLE_RATE_HZ; } // return true if we read any samples - bool loadFrom(FILE *fp) - { + bool loadFrom(FILE *fp) { samplesRemaining = fread((void*)buf, sizeof(Sample_t), SAMPLES_PER_BUFFER, fp); nextSample = buf; return samplesRemaining > 0; } - Sample_t getNextSample() - { + Sample_t getNextSample() { --samplesRemaining; return *++nextSample; } @@ -40,8 +35,7 @@ } }; -struct SongPlayer -{ +struct SongPlayer { SampleBuffer * volatile playing; SampleBuffer * volatile loading; SampleBuffer buffer[2]; @@ -50,29 +44,38 @@ size_t volatile chunksRemaining; float timeInSong; Ticker sampleTicker; + Song *song; + Song::actions_t::iterator nextAction; + unsigned actionsDone; SongPlayer() : playing(0) , loading(0) , fp(0) , nChunks(0) , chunksRemaining(0) - { + , song(0) + , actionsDone(0) + { } // interrupt handler - void playNextSample(void) - { + 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); + bool startSong(Song *_song) { + if (song) delete song; + song = _song; + nextAction = song->getActions().begin(); + timeInSong = 0.0; + actionsDone = 0; + + pc.printf("starting %s: ", song->getSampleFileName()); if (fp) fclose(fp); - fp = fopen(name, "rb"); + fp = fopen(song->getSampleFileName(), "rb"); pc.printf("opened, "); if (!fp) return false; @@ -93,15 +96,14 @@ 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() - { + void swapBuffers() { SampleBuffer * volatile tmp = playing; if (tmp == buffer + 0) playing = buffer + 1; @@ -115,36 +117,35 @@ // get next chunk of file into *loading // to prepare for eventual swap. // returns true if more samples remain - bool loadNextChunk() - { + bool loadNextChunk() { if (!chunksRemaining) return false; bool notDone = loading->loadFrom(fp); return notDone; } - bool isDone() - { + bool isDone() { return !chunksRemaining; } // look at loading buffer; load only if necessary. - bool loadIfNecessary() - { - if (loading->isDone()) - { + bool loadIfNecessary() { + if (loading->isDone()) { timeInSong += SECONDS_PER_CHUNK; return loadNextChunk(); + } else { + return true; } - else { return true; } } - void playEntireSong(char const *name) - { - if (!startSong(name)) return; + void playEntireSong(Song *_song) { + if (!startSong(_song)) return; - while (!isDone()) - { + while (!isDone()) { + while (nextAction != song->getActions().end() && nextAction->actIfPast(timeInSong)) { + actionsDone++; + nextAction++; + } loadIfNecessary(); } sampleTicker.detach();