Big Mouth Billy Bass automation library

Dependents:   BillyBass_with_SD

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();