Big Mouth Billy Bass automation library

Dependents:   BillyBass_with_SD

Committer:
bikeNomad
Date:
Mon Jun 17 22:17:59 2013 +0000
Revision:
0:84aaade0de8f
Child:
2:eaba75af0f0d
Mostly working; hangs when reading actions

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