Big Mouth Billy Bass automation library

Dependents:   BillyBass_with_SD

Committer:
bikeNomad
Date:
Tue Jun 18 06:12:48 2013 +0000
Revision:
2:eaba75af0f0d
Parent:
0:84aaade0de8f
Child:
3:6c91a6232c4a
Still not doing actions but loading OK;

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