Big Mouth Billy Bass automation library

Dependents:   BillyBass_with_SD

Committer:
bikeNomad
Date:
Thu Jun 20 15:03:49 2013 +0000
Revision:
8:ad0c038ebfc1
Parent:
7:dba9221acf48
Made main loop repeat forever; eliminated time shifting

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bikeNomad 0:84aaade0de8f 1 #ifndef __included_player_hpp
bikeNomad 0:84aaade0de8f 2 #define __included_player_hpp
bikeNomad 0:84aaade0de8f 3
bikeNomad 0:84aaade0de8f 4 #include "billybass.hpp"
bikeNomad 0:84aaade0de8f 5
bikeNomad 3:6c91a6232c4a 6 extern AnalogOut speaker;
bikeNomad 3:6c91a6232c4a 7
bikeNomad 0:84aaade0de8f 8 class SongPlayer;
bikeNomad 0:84aaade0de8f 9
bikeNomad 2:eaba75af0f0d 10 struct SampleBuffer {
bikeNomad 0:84aaade0de8f 11 Sample_t volatile buf[ SAMPLES_PER_BUFFER ];
bikeNomad 0:84aaade0de8f 12 size_t volatile samplesRemaining;
bikeNomad 0:84aaade0de8f 13 Sample_t volatile * volatile nextSample;
bikeNomad 0:84aaade0de8f 14
bikeNomad 2:eaba75af0f0d 15 bool isDone() {
bikeNomad 0:84aaade0de8f 16 return !samplesRemaining;
bikeNomad 0:84aaade0de8f 17 }
bikeNomad 0:84aaade0de8f 18
bikeNomad 2:eaba75af0f0d 19 float remainingDuration() {
bikeNomad 0:84aaade0de8f 20 return samplesRemaining / SAMPLE_RATE_HZ;
bikeNomad 0:84aaade0de8f 21 }
bikeNomad 0:84aaade0de8f 22
bikeNomad 0:84aaade0de8f 23 // return true if we read any samples
bikeNomad 2:eaba75af0f0d 24 bool loadFrom(FILE *fp) {
bikeNomad 0:84aaade0de8f 25 samplesRemaining = fread((void*)buf, sizeof(Sample_t), SAMPLES_PER_BUFFER, fp);
bikeNomad 0:84aaade0de8f 26 nextSample = buf;
bikeNomad 0:84aaade0de8f 27 return samplesRemaining > 0;
bikeNomad 0:84aaade0de8f 28 }
bikeNomad 0:84aaade0de8f 29
bikeNomad 2:eaba75af0f0d 30 Sample_t getNextSample() {
bikeNomad 0:84aaade0de8f 31 --samplesRemaining;
bikeNomad 0:84aaade0de8f 32 return *++nextSample;
bikeNomad 0:84aaade0de8f 33 }
bikeNomad 0:84aaade0de8f 34
bikeNomad 0:84aaade0de8f 35 SampleBuffer() : samplesRemaining(0)
bikeNomad 0:84aaade0de8f 36 , nextSample(buf) {
bikeNomad 0:84aaade0de8f 37 }
bikeNomad 0:84aaade0de8f 38 };
bikeNomad 0:84aaade0de8f 39
bikeNomad 2:eaba75af0f0d 40 struct SongPlayer {
bikeNomad 0:84aaade0de8f 41 SampleBuffer * volatile playing;
bikeNomad 0:84aaade0de8f 42 SampleBuffer * volatile loading;
bikeNomad 0:84aaade0de8f 43 SampleBuffer buffer[2];
bikeNomad 0:84aaade0de8f 44 FILE *fp;
bikeNomad 0:84aaade0de8f 45 size_t nChunks;
bikeNomad 0:84aaade0de8f 46 size_t volatile chunksRemaining;
bikeNomad 0:84aaade0de8f 47 float timeInSong;
bikeNomad 0:84aaade0de8f 48 Ticker sampleTicker;
bikeNomad 2:eaba75af0f0d 49 Song *song;
bikeNomad 4:f009306756b3 50 Action *nextAction;
bikeNomad 2:eaba75af0f0d 51 unsigned actionsDone;
bikeNomad 0:84aaade0de8f 52
bikeNomad 0:84aaade0de8f 53 SongPlayer() : playing(0)
bikeNomad 0:84aaade0de8f 54 , loading(0)
bikeNomad 0:84aaade0de8f 55 , fp(0)
bikeNomad 0:84aaade0de8f 56 , nChunks(0)
bikeNomad 0:84aaade0de8f 57 , chunksRemaining(0)
bikeNomad 2:eaba75af0f0d 58 , song(0)
bikeNomad 3:6c91a6232c4a 59 , actionsDone(0) {
bikeNomad 0:84aaade0de8f 60 }
bikeNomad 0:84aaade0de8f 61
bikeNomad 0:84aaade0de8f 62 // interrupt handler
bikeNomad 2:eaba75af0f0d 63 void playNextSample(void) {
bikeNomad 0:84aaade0de8f 64 if (playing->samplesRemaining == 0)
bikeNomad 0:84aaade0de8f 65 swapBuffers();
bikeNomad 0:84aaade0de8f 66 // NOTE bias of 0xC000 requires normalizing to 75% of full scale
bikeNomad 3:6c91a6232c4a 67 speaker.write_u16(static_cast<uint16_t>(playing->getNextSample() + ANALOG_OUTPUT_BIAS));
bikeNomad 0:84aaade0de8f 68 }
bikeNomad 0:84aaade0de8f 69
bikeNomad 2:eaba75af0f0d 70 bool startSong(Song *_song) {
bikeNomad 2:eaba75af0f0d 71 song = _song;
bikeNomad 4:f009306756b3 72 nextAction = song->getActions();
bikeNomad 2:eaba75af0f0d 73 timeInSong = 0.0;
bikeNomad 2:eaba75af0f0d 74 actionsDone = 0;
bikeNomad 2:eaba75af0f0d 75
bikeNomad 3:6c91a6232c4a 76 fprintf(stderr, "starting %s: ", song->getSampleFileName());
bikeNomad 0:84aaade0de8f 77 if (fp) fclose(fp);
bikeNomad 2:eaba75af0f0d 78 fp = fopen(song->getSampleFileName(), "rb");
bikeNomad 4:f009306756b3 79 if (!fp) goto on_error;
bikeNomad 3:6c91a6232c4a 80 fprintf(stderr, "opened, ");
bikeNomad 0:84aaade0de8f 81
bikeNomad 4:f009306756b3 82 if (fseek(fp, 0, SEEK_END)) goto on_error;
bikeNomad 3:6c91a6232c4a 83 fprintf(stderr, "seekend, ");
bikeNomad 0:84aaade0de8f 84
bikeNomad 0:84aaade0de8f 85 long fileSize = ftell(fp);
bikeNomad 3:6c91a6232c4a 86 fprintf(stderr, "size=%d, ", fileSize);
bikeNomad 4:f009306756b3 87 if (fileSize < 0) goto on_error;
bikeNomad 0:84aaade0de8f 88
bikeNomad 4:f009306756b3 89 if (fseek(fp, 0, SEEK_SET)) goto on_error;
bikeNomad 0:84aaade0de8f 90
bikeNomad 3:6c91a6232c4a 91 fprintf(stderr, "rewound, ");
bikeNomad 0:84aaade0de8f 92 chunksRemaining = nChunks = fileSize / BUFFER_SIZE;
bikeNomad 0:84aaade0de8f 93 loading = &buffer[0];
bikeNomad 0:84aaade0de8f 94 playing = &buffer[1];
bikeNomad 3:6c91a6232c4a 95 fprintf(stderr, "chunks=%d expected=%f seconds\r\n", nChunks, nChunks * SECONDS_PER_CHUNK);
bikeNomad 3:6c91a6232c4a 96 if (!loadNextChunk()) {
bikeNomad 3:6c91a6232c4a 97 fprintf(stderr, "first chunk empty!\r\n");
bikeNomad 4:f009306756b3 98 goto on_error;
bikeNomad 3:6c91a6232c4a 99 }
bikeNomad 2:eaba75af0f0d 100
bikeNomad 0:84aaade0de8f 101 sampleTicker.attach_us(this, &SongPlayer::playNextSample, SAMPLE_PERIOD_USEC);
bikeNomad 0:84aaade0de8f 102 return true;
bikeNomad 4:f009306756b3 103
bikeNomad 4:f009306756b3 104 on_error:
bikeNomad 4:f009306756b3 105 if (fp) fclose(fp);
bikeNomad 4:f009306756b3 106 fp = 0;
bikeNomad 4:f009306756b3 107 return false;
bikeNomad 0:84aaade0de8f 108 }
bikeNomad 0:84aaade0de8f 109
bikeNomad 0:84aaade0de8f 110 // swap loading/playing buffers;
bikeNomad 0:84aaade0de8f 111 // decrement chunksRemaining
bikeNomad 2:eaba75af0f0d 112 void swapBuffers() {
bikeNomad 0:84aaade0de8f 113 SampleBuffer * volatile tmp = playing;
bikeNomad 0:84aaade0de8f 114 if (tmp == buffer + 0)
bikeNomad 0:84aaade0de8f 115 playing = buffer + 1;
bikeNomad 0:84aaade0de8f 116 else
bikeNomad 0:84aaade0de8f 117 playing = buffer + 0;
bikeNomad 0:84aaade0de8f 118 loading = tmp;
bikeNomad 0:84aaade0de8f 119 if (chunksRemaining)
bikeNomad 0:84aaade0de8f 120 chunksRemaining--;
bikeNomad 0:84aaade0de8f 121 }
bikeNomad 0:84aaade0de8f 122
bikeNomad 0:84aaade0de8f 123 // get next chunk of file into *loading
bikeNomad 0:84aaade0de8f 124 // to prepare for eventual swap.
bikeNomad 0:84aaade0de8f 125 // returns true if more samples remain
bikeNomad 2:eaba75af0f0d 126 bool loadNextChunk() {
bikeNomad 3:6c91a6232c4a 127 if (isDone())
bikeNomad 3:6c91a6232c4a 128 return false;
bikeNomad 0:84aaade0de8f 129 bool notDone = loading->loadFrom(fp);
bikeNomad 0:84aaade0de8f 130 return notDone;
bikeNomad 0:84aaade0de8f 131 }
bikeNomad 0:84aaade0de8f 132
bikeNomad 2:eaba75af0f0d 133 bool isDone() {
bikeNomad 0:84aaade0de8f 134 return !chunksRemaining;
bikeNomad 0:84aaade0de8f 135 }
bikeNomad 0:84aaade0de8f 136
bikeNomad 0:84aaade0de8f 137 // look at loading buffer; load only if necessary.
bikeNomad 2:eaba75af0f0d 138 bool loadIfNecessary() {
bikeNomad 2:eaba75af0f0d 139 if (loading->isDone()) {
bikeNomad 4:f009306756b3 140 fprintf(stderr, "*");
bikeNomad 0:84aaade0de8f 141 timeInSong += SECONDS_PER_CHUNK;
bikeNomad 0:84aaade0de8f 142 return loadNextChunk();
bikeNomad 2:eaba75af0f0d 143 } else {
bikeNomad 2:eaba75af0f0d 144 return true;
bikeNomad 0:84aaade0de8f 145 }
bikeNomad 0:84aaade0de8f 146 }
bikeNomad 0:84aaade0de8f 147
bikeNomad 2:eaba75af0f0d 148 void playEntireSong(Song *_song) {
bikeNomad 2:eaba75af0f0d 149 if (!startSong(_song)) return;
bikeNomad 4:f009306756b3 150 Action* lastAction = song->getActions() + song->getNumActions();
bikeNomad 2:eaba75af0f0d 151 while (!isDone()) {
bikeNomad 7:dba9221acf48 152 while (nextAction < lastAction && nextAction->isPast(timeInSong)) {
bikeNomad 7:dba9221acf48 153 nextAction->act();
bikeNomad 6:ea8136eb6976 154 fputc(nextAction->code, stderr);
bikeNomad 2:eaba75af0f0d 155 actionsDone++;
bikeNomad 2:eaba75af0f0d 156 nextAction++;
bikeNomad 2:eaba75af0f0d 157 }
bikeNomad 0:84aaade0de8f 158 loadIfNecessary();
bikeNomad 0:84aaade0de8f 159 }
bikeNomad 0:84aaade0de8f 160 sampleTicker.detach();
bikeNomad 3:6c91a6232c4a 161 song->myFish()->relax();
bikeNomad 0:84aaade0de8f 162 }
bikeNomad 0:84aaade0de8f 163 };
bikeNomad 0:84aaade0de8f 164
bikeNomad 0:84aaade0de8f 165 #endif