Chris Dick
/
Gameduino_Invaders_game
Invaders game for the Gameduino
utils.cpp@0:8a7c58553b44, 2012-06-21 (annotated)
- Committer:
- TheChrisyd
- Date:
- Thu Jun 21 19:13:34 2012 +0000
- Revision:
- 0:8a7c58553b44
- Child:
- 1:f44175dd69fd
backup before adding more features
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
TheChrisyd | 0:8a7c58553b44 | 1 | //#include <SPI.h> |
TheChrisyd | 0:8a7c58553b44 | 2 | |
TheChrisyd | 0:8a7c58553b44 | 3 | #include "utils.h" |
TheChrisyd | 0:8a7c58553b44 | 4 | SPI spiutils(ARD_MOSI, ARD_MISO, ARD_SCK); // mosi, miso, sclk |
TheChrisyd | 0:8a7c58553b44 | 5 | Serial pcu(USBTX, USBRX); |
TheChrisyd | 0:8a7c58553b44 | 6 | /*--------------------------------------------- |
TheChrisyd | 0:8a7c58553b44 | 7 | Coprocessor controller |
TheChrisyd | 0:8a7c58553b44 | 8 | ---------------------------------------------*/ |
TheChrisyd | 0:8a7c58553b44 | 9 | enum { |
TheChrisyd | 0:8a7c58553b44 | 10 | COPPERCTRL = COMM, |
TheChrisyd | 0:8a7c58553b44 | 11 | COPPERLISTSTART = COPPERCTRL, |
TheChrisyd | 0:8a7c58553b44 | 12 | SAMPLEREADPOS = COPPERCTRL+2, |
TheChrisyd | 0:8a7c58553b44 | 13 | SAMPLEREADPAGE = COPPERCTRL+4, |
TheChrisyd | 0:8a7c58553b44 | 14 | COPPERLISTPTR = COPPERCTRL+6, |
TheChrisyd | 0:8a7c58553b44 | 15 | YLINEECHO = COPPERCTRL+8, |
TheChrisyd | 0:8a7c58553b44 | 16 | DUMMYCOPPERLIST = COPPERCTRL+10 |
TheChrisyd | 0:8a7c58553b44 | 17 | }; |
TheChrisyd | 0:8a7c58553b44 | 18 | |
TheChrisyd | 0:8a7c58553b44 | 19 | // Available commands |
TheChrisyd | 0:8a7c58553b44 | 20 | enum copper_commands { |
TheChrisyd | 0:8a7c58553b44 | 21 | cp_halt='@', |
TheChrisyd | 0:8a7c58553b44 | 22 | cp_wait, |
TheChrisyd | 0:8a7c58553b44 | 23 | cp_write8, |
TheChrisyd | 0:8a7c58553b44 | 24 | cp_write16, |
TheChrisyd | 0:8a7c58553b44 | 25 | cp_copy |
TheChrisyd | 0:8a7c58553b44 | 26 | }; |
TheChrisyd | 0:8a7c58553b44 | 27 | |
TheChrisyd | 0:8a7c58553b44 | 28 | #include "j1.h" |
TheChrisyd | 0:8a7c58553b44 | 29 | void crash() |
TheChrisyd | 0:8a7c58553b44 | 30 | { |
TheChrisyd | 0:8a7c58553b44 | 31 | unsigned int p; |
TheChrisyd | 0:8a7c58553b44 | 32 | while (1) { |
TheChrisyd | 0:8a7c58553b44 | 33 | GD.wr(0,p++); |
TheChrisyd | 0:8a7c58553b44 | 34 | } |
TheChrisyd | 0:8a7c58553b44 | 35 | } |
TheChrisyd | 0:8a7c58553b44 | 36 | static unsigned int samplePage_, listStart_; |
TheChrisyd | 0:8a7c58553b44 | 37 | void Coprocessor::reset(unsigned int spg) |
TheChrisyd | 0:8a7c58553b44 | 38 | { |
TheChrisyd | 0:8a7c58553b44 | 39 | samplePage_ = spg; |
TheChrisyd | 0:8a7c58553b44 | 40 | GD.wr(J1_RESET, 1); // Halt the coprocessor |
TheChrisyd | 0:8a7c58553b44 | 41 | GD.copy(J1_CODE, copper_code, sizeof(copper_code)); |
TheChrisyd | 0:8a7c58553b44 | 42 | for (unsigned int i=J1_CODE; i<J1_CODE+256; i+=2) { |
TheChrisyd | 0:8a7c58553b44 | 43 | unsigned int w = GD.rd16(i); |
TheChrisyd | 0:8a7c58553b44 | 44 | if (w == 0xbf00) { GD.wr16(i,spg+0x8000); } |
TheChrisyd | 0:8a7c58553b44 | 45 | else if (w == COMM+0x8000) { listStart_ = i; } |
TheChrisyd | 0:8a7c58553b44 | 46 | } |
TheChrisyd | 0:8a7c58553b44 | 47 | CopperlistBuilder d; // Set up a fake copperlist |
TheChrisyd | 0:8a7c58553b44 | 48 | GD.wr(DUMMYCOPPERLIST,cp_halt); |
TheChrisyd | 0:8a7c58553b44 | 49 | GD.wr16(listStart_,DUMMYCOPPERLIST+0x8000); |
TheChrisyd | 0:8a7c58553b44 | 50 | GD.wr16(SAMPLEREADPAGE,samplePage_); |
TheChrisyd | 0:8a7c58553b44 | 51 | SoundController::reset(); |
TheChrisyd | 0:8a7c58553b44 | 52 | GD.wr(J1_RESET, 0); // Go! |
TheChrisyd | 0:8a7c58553b44 | 53 | delay(10); |
TheChrisyd | 0:8a7c58553b44 | 54 | SoundController::update(); |
TheChrisyd | 0:8a7c58553b44 | 55 | } |
TheChrisyd | 0:8a7c58553b44 | 56 | |
TheChrisyd | 0:8a7c58553b44 | 57 | void Coprocessor::setCopperlist(unsigned int addr) |
TheChrisyd | 0:8a7c58553b44 | 58 | { |
TheChrisyd | 0:8a7c58553b44 | 59 | GD.wr(J1_RESET, 1); // Halt the coprocessor |
TheChrisyd | 0:8a7c58553b44 | 60 | GD.wr16(listStart_,addr+0x8000); |
TheChrisyd | 0:8a7c58553b44 | 61 | GD.wr(J1_RESET, 0); // Go! |
TheChrisyd | 0:8a7c58553b44 | 62 | } |
TheChrisyd | 0:8a7c58553b44 | 63 | |
TheChrisyd | 0:8a7c58553b44 | 64 | int Coprocessor::yline() |
TheChrisyd | 0:8a7c58553b44 | 65 | { |
TheChrisyd | 0:8a7c58553b44 | 66 | return GD.rd16(YLINEECHO); |
TheChrisyd | 0:8a7c58553b44 | 67 | } |
TheChrisyd | 0:8a7c58553b44 | 68 | unsigned int Coprocessor::samplePage() |
TheChrisyd | 0:8a7c58553b44 | 69 | { |
TheChrisyd | 0:8a7c58553b44 | 70 | return samplePage_; |
TheChrisyd | 0:8a7c58553b44 | 71 | } |
TheChrisyd | 0:8a7c58553b44 | 72 | byte Coprocessor::sampleReadPos() |
TheChrisyd | 0:8a7c58553b44 | 73 | { |
TheChrisyd | 0:8a7c58553b44 | 74 | return GD.rd(SAMPLEREADPOS); |
TheChrisyd | 0:8a7c58553b44 | 75 | } |
TheChrisyd | 0:8a7c58553b44 | 76 | |
TheChrisyd | 0:8a7c58553b44 | 77 | // CopperlistBuilder |
TheChrisyd | 0:8a7c58553b44 | 78 | void CopperlistBuilder::put(byte b) |
TheChrisyd | 0:8a7c58553b44 | 79 | { |
TheChrisyd | 0:8a7c58553b44 | 80 | GD.wr(out++,b); |
TheChrisyd | 0:8a7c58553b44 | 81 | } |
TheChrisyd | 0:8a7c58553b44 | 82 | void CopperlistBuilder::put16(unsigned int v) |
TheChrisyd | 0:8a7c58553b44 | 83 | { |
TheChrisyd | 0:8a7c58553b44 | 84 | put(lowByte(v)); |
TheChrisyd | 0:8a7c58553b44 | 85 | put(highByte(v)); |
TheChrisyd | 0:8a7c58553b44 | 86 | } |
TheChrisyd | 0:8a7c58553b44 | 87 | |
TheChrisyd | 0:8a7c58553b44 | 88 | void CopperlistBuilder::begin(unsigned int dest) |
TheChrisyd | 0:8a7c58553b44 | 89 | { |
TheChrisyd | 0:8a7c58553b44 | 90 | out = start = dest; |
TheChrisyd | 0:8a7c58553b44 | 91 | #if 0 |
TheChrisyd | 0:8a7c58553b44 | 92 | // Debugging... |
TheChrisyd | 0:8a7c58553b44 | 93 | write(0,65); |
TheChrisyd | 0:8a7c58553b44 | 94 | write(1,66); |
TheChrisyd | 0:8a7c58553b44 | 95 | write(2,67); |
TheChrisyd | 0:8a7c58553b44 | 96 | write(3,68); |
TheChrisyd | 0:8a7c58553b44 | 97 | write(4,69); |
TheChrisyd | 0:8a7c58553b44 | 98 | copy(0,64,4); |
TheChrisyd | 0:8a7c58553b44 | 99 | copy(64,128,3); |
TheChrisyd | 0:8a7c58553b44 | 100 | copy(128,131,5); |
TheChrisyd | 0:8a7c58553b44 | 101 | #endif |
TheChrisyd | 0:8a7c58553b44 | 102 | } |
TheChrisyd | 0:8a7c58553b44 | 103 | void CopperlistBuilder::wait(int line) |
TheChrisyd | 0:8a7c58553b44 | 104 | { |
TheChrisyd | 0:8a7c58553b44 | 105 | if (line > 0) { |
TheChrisyd | 0:8a7c58553b44 | 106 | put(cp_wait); |
TheChrisyd | 0:8a7c58553b44 | 107 | put16(line); |
TheChrisyd | 0:8a7c58553b44 | 108 | } |
TheChrisyd | 0:8a7c58553b44 | 109 | } |
TheChrisyd | 0:8a7c58553b44 | 110 | void CopperlistBuilder::write(unsigned int addr, byte val) |
TheChrisyd | 0:8a7c58553b44 | 111 | { |
TheChrisyd | 0:8a7c58553b44 | 112 | put(cp_write8); |
TheChrisyd | 0:8a7c58553b44 | 113 | put(val); |
TheChrisyd | 0:8a7c58553b44 | 114 | put16(addr); |
TheChrisyd | 0:8a7c58553b44 | 115 | } |
TheChrisyd | 0:8a7c58553b44 | 116 | void CopperlistBuilder::write16(unsigned int addr, unsigned int val) |
TheChrisyd | 0:8a7c58553b44 | 117 | { |
TheChrisyd | 0:8a7c58553b44 | 118 | put(cp_write16); |
TheChrisyd | 0:8a7c58553b44 | 119 | put16(val); |
TheChrisyd | 0:8a7c58553b44 | 120 | put16(addr); |
TheChrisyd | 0:8a7c58553b44 | 121 | } |
TheChrisyd | 0:8a7c58553b44 | 122 | void CopperlistBuilder::copy(unsigned int src, unsigned int dst, unsigned int numBytes) |
TheChrisyd | 0:8a7c58553b44 | 123 | { |
TheChrisyd | 0:8a7c58553b44 | 124 | if (numBytes > 0) { |
TheChrisyd | 0:8a7c58553b44 | 125 | put(cp_copy); |
TheChrisyd | 0:8a7c58553b44 | 126 | put16(src); |
TheChrisyd | 0:8a7c58553b44 | 127 | put16(dst); |
TheChrisyd | 0:8a7c58553b44 | 128 | put16(numBytes); |
TheChrisyd | 0:8a7c58553b44 | 129 | } |
TheChrisyd | 0:8a7c58553b44 | 130 | } |
TheChrisyd | 0:8a7c58553b44 | 131 | void CopperlistBuilder::end(bool executeNow) |
TheChrisyd | 0:8a7c58553b44 | 132 | { |
TheChrisyd | 0:8a7c58553b44 | 133 | put(cp_halt); // Nice end to the list |
TheChrisyd | 0:8a7c58553b44 | 134 | if (executeNow) { |
TheChrisyd | 0:8a7c58553b44 | 135 | Coprocessor::setCopperlist(start); |
TheChrisyd | 0:8a7c58553b44 | 136 | } |
TheChrisyd | 0:8a7c58553b44 | 137 | } |
TheChrisyd | 0:8a7c58553b44 | 138 | |
TheChrisyd | 0:8a7c58553b44 | 139 | unsigned int CopperlistBuilder::position() |
TheChrisyd | 0:8a7c58553b44 | 140 | { |
TheChrisyd | 0:8a7c58553b44 | 141 | return out; |
TheChrisyd | 0:8a7c58553b44 | 142 | } |
TheChrisyd | 0:8a7c58553b44 | 143 | |
TheChrisyd | 0:8a7c58553b44 | 144 | /*--------------------------------------------- |
TheChrisyd | 0:8a7c58553b44 | 145 | Sound |
TheChrisyd | 0:8a7c58553b44 | 146 | ---------------------------------------------*/ |
TheChrisyd | 0:8a7c58553b44 | 147 | // The amount of space to leave in the buffer |
TheChrisyd | 0:8a7c58553b44 | 148 | #define BUFFERGAP 8 |
TheChrisyd | 0:8a7c58553b44 | 149 | |
TheChrisyd | 0:8a7c58553b44 | 150 | /*--------------------------------------------- |
TheChrisyd | 0:8a7c58553b44 | 151 | Sample playback |
TheChrisyd | 0:8a7c58553b44 | 152 | ---------------------------------------------*/ |
TheChrisyd | 0:8a7c58553b44 | 153 | static byte sampleWritePos; |
TheChrisyd | 0:8a7c58553b44 | 154 | static prog_char *sampleStart0, *samplePos0, *sampleEnd0; |
TheChrisyd | 0:8a7c58553b44 | 155 | static prog_char *sampleStart1, *samplePos1, *sampleEnd1; |
TheChrisyd | 0:8a7c58553b44 | 156 | static prog_char *sampleStart2, *samplePos2, *sampleEnd2; |
TheChrisyd | 0:8a7c58553b44 | 157 | static prog_char *sampleStart3, *samplePos3, *sampleEnd3; |
TheChrisyd | 0:8a7c58553b44 | 158 | static bool repeatSample0, repeatSample1, repeatSample2, repeatSample3; |
TheChrisyd | 0:8a7c58553b44 | 159 | |
TheChrisyd | 0:8a7c58553b44 | 160 | static void writeSamples(byte num) |
TheChrisyd | 0:8a7c58553b44 | 161 | { |
TheChrisyd | 0:8a7c58553b44 | 162 | if (num > 0) { |
TheChrisyd | 0:8a7c58553b44 | 163 | GD.__wstart(Coprocessor::samplePage()+sampleWritePos); |
TheChrisyd | 0:8a7c58553b44 | 164 | prog_char *s0=samplePos0, *se0=sampleEnd0; |
TheChrisyd | 0:8a7c58553b44 | 165 | prog_char *s1=samplePos1, *se1=sampleEnd1; |
TheChrisyd | 0:8a7c58553b44 | 166 | prog_char *s2=samplePos2, *se2=sampleEnd2; |
TheChrisyd | 0:8a7c58553b44 | 167 | prog_char *s3=samplePos3, *se3=sampleEnd3; |
TheChrisyd | 0:8a7c58553b44 | 168 | for (byte i=0; i<num; ++i) { |
TheChrisyd | 0:8a7c58553b44 | 169 | int val = 0; |
TheChrisyd | 0:8a7c58553b44 | 170 | if (s0) { |
TheChrisyd | 0:8a7c58553b44 | 171 | val += (char)pgm_read_byte(s0++); |
TheChrisyd | 0:8a7c58553b44 | 172 | if (s0 == se0) { |
TheChrisyd | 0:8a7c58553b44 | 173 | s0 = (repeatSample0)? sampleStart0: 0; |
TheChrisyd | 0:8a7c58553b44 | 174 | } |
TheChrisyd | 0:8a7c58553b44 | 175 | } |
TheChrisyd | 0:8a7c58553b44 | 176 | if (s1) { |
TheChrisyd | 0:8a7c58553b44 | 177 | val += (char)pgm_read_byte(s1++); |
TheChrisyd | 0:8a7c58553b44 | 178 | if (s1 == se1) { |
TheChrisyd | 0:8a7c58553b44 | 179 | s1 = (repeatSample1)? sampleStart1: 0; |
TheChrisyd | 0:8a7c58553b44 | 180 | } |
TheChrisyd | 0:8a7c58553b44 | 181 | } |
TheChrisyd | 0:8a7c58553b44 | 182 | if (s2) { |
TheChrisyd | 0:8a7c58553b44 | 183 | val += (char)pgm_read_byte(s2++); |
TheChrisyd | 0:8a7c58553b44 | 184 | if (s2 == se2) { |
TheChrisyd | 0:8a7c58553b44 | 185 | s2 = (repeatSample2)? sampleStart2: 0; |
TheChrisyd | 0:8a7c58553b44 | 186 | } |
TheChrisyd | 0:8a7c58553b44 | 187 | } |
TheChrisyd | 0:8a7c58553b44 | 188 | if (s3) { |
TheChrisyd | 0:8a7c58553b44 | 189 | val += (char)pgm_read_byte(s3++); |
TheChrisyd | 0:8a7c58553b44 | 190 | if (s3 == se3) { |
TheChrisyd | 0:8a7c58553b44 | 191 | s3 = (repeatSample3)? sampleStart3: 0; |
TheChrisyd | 0:8a7c58553b44 | 192 | } |
TheChrisyd | 0:8a7c58553b44 | 193 | } |
TheChrisyd | 0:8a7c58553b44 | 194 | spiutils.write(val>>2); |
TheChrisyd | 0:8a7c58553b44 | 195 | } |
TheChrisyd | 0:8a7c58553b44 | 196 | GD.__end(); |
TheChrisyd | 0:8a7c58553b44 | 197 | samplePos0 = s0; |
TheChrisyd | 0:8a7c58553b44 | 198 | samplePos1 = s1; |
TheChrisyd | 0:8a7c58553b44 | 199 | samplePos2 = s2; |
TheChrisyd | 0:8a7c58553b44 | 200 | samplePos3 = s3; |
TheChrisyd | 0:8a7c58553b44 | 201 | sampleWritePos += num; |
TheChrisyd | 0:8a7c58553b44 | 202 | } |
TheChrisyd | 0:8a7c58553b44 | 203 | } |
TheChrisyd | 0:8a7c58553b44 | 204 | |
TheChrisyd | 0:8a7c58553b44 | 205 | void SoundController::playSample(prog_char *s, int n, byte ch) |
TheChrisyd | 0:8a7c58553b44 | 206 | { |
TheChrisyd | 0:8a7c58553b44 | 207 | bool repeat = (n < 0); |
TheChrisyd | 0:8a7c58553b44 | 208 | if (repeat) { |
TheChrisyd | 0:8a7c58553b44 | 209 | n = -n; |
TheChrisyd | 0:8a7c58553b44 | 210 | } |
TheChrisyd | 0:8a7c58553b44 | 211 | switch (ch) { |
TheChrisyd | 0:8a7c58553b44 | 212 | case 0: sampleStart0 = s; |
TheChrisyd | 0:8a7c58553b44 | 213 | samplePos0 = s; |
TheChrisyd | 0:8a7c58553b44 | 214 | sampleEnd0 = s+n; |
TheChrisyd | 0:8a7c58553b44 | 215 | repeatSample0 = repeat; |
TheChrisyd | 0:8a7c58553b44 | 216 | break; |
TheChrisyd | 0:8a7c58553b44 | 217 | case 1: sampleStart1 = s; |
TheChrisyd | 0:8a7c58553b44 | 218 | samplePos1 = s; |
TheChrisyd | 0:8a7c58553b44 | 219 | sampleEnd1 = s+n; |
TheChrisyd | 0:8a7c58553b44 | 220 | repeatSample1 = repeat; |
TheChrisyd | 0:8a7c58553b44 | 221 | break; |
TheChrisyd | 0:8a7c58553b44 | 222 | case 2: sampleStart2 = s; |
TheChrisyd | 0:8a7c58553b44 | 223 | samplePos2 = s; |
TheChrisyd | 0:8a7c58553b44 | 224 | sampleEnd2 = s+n; |
TheChrisyd | 0:8a7c58553b44 | 225 | repeatSample2 = repeat; |
TheChrisyd | 0:8a7c58553b44 | 226 | break; |
TheChrisyd | 0:8a7c58553b44 | 227 | case 3: sampleStart3 = s; |
TheChrisyd | 0:8a7c58553b44 | 228 | samplePos3 = s; |
TheChrisyd | 0:8a7c58553b44 | 229 | sampleEnd3 = s+n; |
TheChrisyd | 0:8a7c58553b44 | 230 | repeatSample3 = repeat; |
TheChrisyd | 0:8a7c58553b44 | 231 | break; |
TheChrisyd | 0:8a7c58553b44 | 232 | } |
TheChrisyd | 0:8a7c58553b44 | 233 | } |
TheChrisyd | 0:8a7c58553b44 | 234 | |
TheChrisyd | 0:8a7c58553b44 | 235 | #if SYNTHSOUNDS |
TheChrisyd | 0:8a7c58553b44 | 236 | /*--------------------------------------------- |
TheChrisyd | 0:8a7c58553b44 | 237 | Synthesized sounds |
TheChrisyd | 0:8a7c58553b44 | 238 | ---------------------------------------------*/ |
TheChrisyd | 0:8a7c58553b44 | 239 | static SoundPlayer *soundPlayerList=0; |
TheChrisyd | 0:8a7c58553b44 | 240 | ADSR::ADSR(byte a, byte d, byte s, byte r) : attack(a), decay(d), sustain(s), release(r) |
TheChrisyd | 0:8a7c58553b44 | 241 | { |
TheChrisyd | 0:8a7c58553b44 | 242 | } |
TheChrisyd | 0:8a7c58553b44 | 243 | byte ADSR::evaluate(unsigned int t, unsigned int r) |
TheChrisyd | 0:8a7c58553b44 | 244 | { |
TheChrisyd | 0:8a7c58553b44 | 245 | if (t > r) { |
TheChrisyd | 0:8a7c58553b44 | 246 | // In release phase... |
TheChrisyd | 0:8a7c58553b44 | 247 | t -= r; |
TheChrisyd | 0:8a7c58553b44 | 248 | if (t > release) { |
TheChrisyd | 0:8a7c58553b44 | 249 | return 0; |
TheChrisyd | 0:8a7c58553b44 | 250 | } |
TheChrisyd | 0:8a7c58553b44 | 251 | t = sustain*(release-t); |
TheChrisyd | 0:8a7c58553b44 | 252 | return t/release; |
TheChrisyd | 0:8a7c58553b44 | 253 | } |
TheChrisyd | 0:8a7c58553b44 | 254 | else if (t >= (attack+decay)) { |
TheChrisyd | 0:8a7c58553b44 | 255 | // In sustain phase |
TheChrisyd | 0:8a7c58553b44 | 256 | return sustain; |
TheChrisyd | 0:8a7c58553b44 | 257 | } |
TheChrisyd | 0:8a7c58553b44 | 258 | else if (t > attack) { |
TheChrisyd | 0:8a7c58553b44 | 259 | // In decay phase |
TheChrisyd | 0:8a7c58553b44 | 260 | t -= attack; |
TheChrisyd | 0:8a7c58553b44 | 261 | t = (255-sustain)*t; |
TheChrisyd | 0:8a7c58553b44 | 262 | return 255-(t/decay); |
TheChrisyd | 0:8a7c58553b44 | 263 | } |
TheChrisyd | 0:8a7c58553b44 | 264 | else if (t > 0) { |
TheChrisyd | 0:8a7c58553b44 | 265 | // In attack phase |
TheChrisyd | 0:8a7c58553b44 | 266 | return (t*255)/attack; |
TheChrisyd | 0:8a7c58553b44 | 267 | } |
TheChrisyd | 0:8a7c58553b44 | 268 | return 0; |
TheChrisyd | 0:8a7c58553b44 | 269 | } |
TheChrisyd | 0:8a7c58553b44 | 270 | |
TheChrisyd | 0:8a7c58553b44 | 271 | SoundPlayer::SoundPlayer() |
TheChrisyd | 0:8a7c58553b44 | 272 | { |
TheChrisyd | 0:8a7c58553b44 | 273 | volume = 255; |
TheChrisyd | 0:8a7c58553b44 | 274 | active = false; |
TheChrisyd | 0:8a7c58553b44 | 275 | isLinked = false; |
TheChrisyd | 0:8a7c58553b44 | 276 | } |
TheChrisyd | 0:8a7c58553b44 | 277 | SoundPlayer& SoundPlayer::setVolume(byte v) |
TheChrisyd | 0:8a7c58553b44 | 278 | { |
TheChrisyd | 0:8a7c58553b44 | 279 | volume = v; |
TheChrisyd | 0:8a7c58553b44 | 280 | return *this; |
TheChrisyd | 0:8a7c58553b44 | 281 | } |
TheChrisyd | 0:8a7c58553b44 | 282 | SoundPlayer& SoundPlayer::setSound(const Sound& s) |
TheChrisyd | 0:8a7c58553b44 | 283 | { |
TheChrisyd | 0:8a7c58553b44 | 284 | sound = s; |
TheChrisyd | 0:8a7c58553b44 | 285 | return *this; |
TheChrisyd | 0:8a7c58553b44 | 286 | } |
TheChrisyd | 0:8a7c58553b44 | 287 | void SoundPlayer::play(unsigned int p, unsigned int d) |
TheChrisyd | 0:8a7c58553b44 | 288 | { |
TheChrisyd | 0:8a7c58553b44 | 289 | if (!isLinked) { |
TheChrisyd | 0:8a7c58553b44 | 290 | // Add me to the list of sounds to be updated |
TheChrisyd | 0:8a7c58553b44 | 291 | isLinked = true; |
TheChrisyd | 0:8a7c58553b44 | 292 | link = soundPlayerList; |
TheChrisyd | 0:8a7c58553b44 | 293 | soundPlayerList = this; |
TheChrisyd | 0:8a7c58553b44 | 294 | } |
TheChrisyd | 0:8a7c58553b44 | 295 | ticks = 0; |
TheChrisyd | 0:8a7c58553b44 | 296 | pitch = p; |
TheChrisyd | 0:8a7c58553b44 | 297 | duration = d; |
TheChrisyd | 0:8a7c58553b44 | 298 | releasing = false; |
TheChrisyd | 0:8a7c58553b44 | 299 | active = true; |
TheChrisyd | 0:8a7c58553b44 | 300 | } |
TheChrisyd | 0:8a7c58553b44 | 301 | void SoundPlayer::release() |
TheChrisyd | 0:8a7c58553b44 | 302 | { |
TheChrisyd | 0:8a7c58553b44 | 303 | releasing = true; |
TheChrisyd | 0:8a7c58553b44 | 304 | duration = ticks; |
TheChrisyd | 0:8a7c58553b44 | 305 | } |
TheChrisyd | 0:8a7c58553b44 | 306 | void SoundPlayer::update() |
TheChrisyd | 0:8a7c58553b44 | 307 | { |
TheChrisyd | 0:8a7c58553b44 | 308 | if (active) { |
TheChrisyd | 0:8a7c58553b44 | 309 | if (releasing) { |
TheChrisyd | 0:8a7c58553b44 | 310 | if (++ticks > (duration+sound.adsr.release)) { |
TheChrisyd | 0:8a7c58553b44 | 311 | stop(); |
TheChrisyd | 0:8a7c58553b44 | 312 | } |
TheChrisyd | 0:8a7c58553b44 | 313 | } |
TheChrisyd | 0:8a7c58553b44 | 314 | else { |
TheChrisyd | 0:8a7c58553b44 | 315 | if (ticks!=infinite) { |
TheChrisyd | 0:8a7c58553b44 | 316 | ++ticks; |
TheChrisyd | 0:8a7c58553b44 | 317 | } |
TheChrisyd | 0:8a7c58553b44 | 318 | if ((ticks==duration) and (duration!=infinite)) { |
TheChrisyd | 0:8a7c58553b44 | 319 | release(); |
TheChrisyd | 0:8a7c58553b44 | 320 | } |
TheChrisyd | 0:8a7c58553b44 | 321 | } |
TheChrisyd | 0:8a7c58553b44 | 322 | if (active) { |
TheChrisyd | 0:8a7c58553b44 | 323 | GD.__wstart(VOICES); |
TheChrisyd | 0:8a7c58553b44 | 324 | spimain.write(lowByte(pitch)); |
TheChrisyd | 0:8a7c58553b44 | 325 | spimain.write(highByte(pitch)); |
TheChrisyd | 0:8a7c58553b44 | 326 | unsigned int b = sound.adsr.evaluate(ticks,duration); |
TheChrisyd | 0:8a7c58553b44 | 327 | b = highByte(b*volume); |
TheChrisyd | 0:8a7c58553b44 | 328 | //spimain.write(b); |
TheChrisyd | 0:8a7c58553b44 | 329 | //spimain.write(b); |
TheChrisyd | 0:8a7c58553b44 | 330 | GD.__end(); |
TheChrisyd | 0:8a7c58553b44 | 331 | } |
TheChrisyd | 0:8a7c58553b44 | 332 | } |
TheChrisyd | 0:8a7c58553b44 | 333 | } |
TheChrisyd | 0:8a7c58553b44 | 334 | void SoundPlayer::stop() |
TheChrisyd | 0:8a7c58553b44 | 335 | { |
TheChrisyd | 0:8a7c58553b44 | 336 | if (active) { |
TheChrisyd | 0:8a7c58553b44 | 337 | active = false; |
TheChrisyd | 0:8a7c58553b44 | 338 | GD.__wstart(VOICES+2); |
TheChrisyd | 0:8a7c58553b44 | 339 | spimain.write(0); |
TheChrisyd | 0:8a7c58553b44 | 340 | spimain.write(0); |
TheChrisyd | 0:8a7c58553b44 | 341 | GD.__end(); |
TheChrisyd | 0:8a7c58553b44 | 342 | } |
TheChrisyd | 0:8a7c58553b44 | 343 | } |
TheChrisyd | 0:8a7c58553b44 | 344 | #endif |
TheChrisyd | 0:8a7c58553b44 | 345 | /*--------------------------------------------- |
TheChrisyd | 0:8a7c58553b44 | 346 | SoundController object |
TheChrisyd | 0:8a7c58553b44 | 347 | ---------------------------------------------*/ |
TheChrisyd | 0:8a7c58553b44 | 348 | void SoundController::reset() |
TheChrisyd | 0:8a7c58553b44 | 349 | { |
TheChrisyd | 0:8a7c58553b44 | 350 | samplePos0 = 0; |
TheChrisyd | 0:8a7c58553b44 | 351 | samplePos1 = 0; |
TheChrisyd | 0:8a7c58553b44 | 352 | samplePos2 = 0; |
TheChrisyd | 0:8a7c58553b44 | 353 | samplePos3 = 0; |
TheChrisyd | 0:8a7c58553b44 | 354 | GD.__wstart(Coprocessor::samplePage()); |
TheChrisyd | 0:8a7c58553b44 | 355 | for (int i=0; i<256; ++i) { |
TheChrisyd | 0:8a7c58553b44 | 356 | spiutils.write(0); |
TheChrisyd | 0:8a7c58553b44 | 357 | } |
TheChrisyd | 0:8a7c58553b44 | 358 | GD.__end(); |
TheChrisyd | 0:8a7c58553b44 | 359 | #if SYNTHSOUNDS |
TheChrisyd | 0:8a7c58553b44 | 360 | SoundPlayer *p = soundPlayerList; |
TheChrisyd | 0:8a7c58553b44 | 361 | while (p) { |
TheChrisyd | 0:8a7c58553b44 | 362 | p->stop(); |
TheChrisyd | 0:8a7c58553b44 | 363 | p->isLinked = false; |
TheChrisyd | 0:8a7c58553b44 | 364 | p = p->link; |
TheChrisyd | 0:8a7c58553b44 | 365 | } |
TheChrisyd | 0:8a7c58553b44 | 366 | #endif |
TheChrisyd | 0:8a7c58553b44 | 367 | } |
TheChrisyd | 0:8a7c58553b44 | 368 | |
TheChrisyd | 0:8a7c58553b44 | 369 | void SoundController::update() |
TheChrisyd | 0:8a7c58553b44 | 370 | { |
TheChrisyd | 0:8a7c58553b44 | 371 | #if SYNTHSOUNDS |
TheChrisyd | 0:8a7c58553b44 | 372 | { // Synthesized sounds |
TheChrisyd | 0:8a7c58553b44 | 373 | byte b = '0'; |
TheChrisyd | 0:8a7c58553b44 | 374 | SoundPlayer *p = soundPlayerList; |
TheChrisyd | 0:8a7c58553b44 | 375 | while (p) { |
TheChrisyd | 0:8a7c58553b44 | 376 | ++b; |
TheChrisyd | 0:8a7c58553b44 | 377 | p->update(); |
TheChrisyd | 0:8a7c58553b44 | 378 | p = p->link; |
TheChrisyd | 0:8a7c58553b44 | 379 | } |
TheChrisyd | 0:8a7c58553b44 | 380 | GD.wr(0,b); |
TheChrisyd | 0:8a7c58553b44 | 381 | } |
TheChrisyd | 0:8a7c58553b44 | 382 | #endif |
TheChrisyd | 0:8a7c58553b44 | 383 | { // Sampled sounds |
TheChrisyd | 0:8a7c58553b44 | 384 | unsigned int rp = Coprocessor::sampleReadPos(); |
TheChrisyd | 0:8a7c58553b44 | 385 | unsigned int wp = sampleWritePos; |
TheChrisyd | 0:8a7c58553b44 | 386 | unsigned int emptySpace = (rp-wp)&255; |
TheChrisyd | 0:8a7c58553b44 | 387 | if (emptySpace > BUFFERGAP) { |
TheChrisyd | 0:8a7c58553b44 | 388 | emptySpace -= BUFFERGAP; |
TheChrisyd | 0:8a7c58553b44 | 389 | if ((wp+emptySpace) > 256) { |
TheChrisyd | 0:8a7c58553b44 | 390 | // Write would overflow the buffer - need to split it into two |
TheChrisyd | 0:8a7c58553b44 | 391 | unsigned int b = 256-wp; |
TheChrisyd | 0:8a7c58553b44 | 392 | writeSamples(b); |
TheChrisyd | 0:8a7c58553b44 | 393 | writeSamples(emptySpace-b); |
TheChrisyd | 0:8a7c58553b44 | 394 | } |
TheChrisyd | 0:8a7c58553b44 | 395 | else { |
TheChrisyd | 0:8a7c58553b44 | 396 | // Can write a single block |
TheChrisyd | 0:8a7c58553b44 | 397 | writeSamples(emptySpace); |
TheChrisyd | 0:8a7c58553b44 | 398 | } |
TheChrisyd | 0:8a7c58553b44 | 399 | } |
TheChrisyd | 0:8a7c58553b44 | 400 | } |
TheChrisyd | 0:8a7c58553b44 | 401 | } |
TheChrisyd | 0:8a7c58553b44 | 402 | |
TheChrisyd | 0:8a7c58553b44 | 403 | |
TheChrisyd | 0:8a7c58553b44 | 404 | /*------------------------------------------------------------ |
TheChrisyd | 0:8a7c58553b44 | 405 | Useful little functions |
TheChrisyd | 0:8a7c58553b44 | 406 | ------------------------------------------------------------*/ |
TheChrisyd | 0:8a7c58553b44 | 407 | void showNumber(int n, byte x, byte y) |
TheChrisyd | 0:8a7c58553b44 | 408 | { |
TheChrisyd | 0:8a7c58553b44 | 409 | char temp[8]; |
TheChrisyd | 0:8a7c58553b44 | 410 | boolean neg = (n<0); |
TheChrisyd | 0:8a7c58553b44 | 411 | if (neg) { |
TheChrisyd | 0:8a7c58553b44 | 412 | n = -n; |
TheChrisyd | 0:8a7c58553b44 | 413 | } |
TheChrisyd | 0:8a7c58553b44 | 414 | char *o = temp; |
TheChrisyd | 0:8a7c58553b44 | 415 | int m = 10000; |
TheChrisyd | 0:8a7c58553b44 | 416 | while (m != 0) { |
TheChrisyd | 0:8a7c58553b44 | 417 | int d = n/m; |
TheChrisyd | 0:8a7c58553b44 | 418 | *o++ = d+'0'; |
TheChrisyd | 0:8a7c58553b44 | 419 | n -= d*m; |
TheChrisyd | 0:8a7c58553b44 | 420 | m /= 10; |
TheChrisyd | 0:8a7c58553b44 | 421 | } |
TheChrisyd | 0:8a7c58553b44 | 422 | *o-- = 0; |
TheChrisyd | 0:8a7c58553b44 | 423 | // Remove leading zeros |
TheChrisyd | 0:8a7c58553b44 | 424 | char *s = temp; |
TheChrisyd | 0:8a7c58553b44 | 425 | while ((s<o) and (*s=='0')) { |
TheChrisyd | 0:8a7c58553b44 | 426 | *s++ = ' '; |
TheChrisyd | 0:8a7c58553b44 | 427 | } |
TheChrisyd | 0:8a7c58553b44 | 428 | if (neg) { |
TheChrisyd | 0:8a7c58553b44 | 429 | *--s = '-'; |
TheChrisyd | 0:8a7c58553b44 | 430 | } |
TheChrisyd | 0:8a7c58553b44 | 431 | GD.__wstart((64*y)+x); |
TheChrisyd | 0:8a7c58553b44 | 432 | while (*s) { |
TheChrisyd | 0:8a7c58553b44 | 433 | spiutils.write(*s++); |
TheChrisyd | 0:8a7c58553b44 | 434 | } |
TheChrisyd | 0:8a7c58553b44 | 435 | GD.__end(); |
TheChrisyd | 0:8a7c58553b44 | 436 | } |
TheChrisyd | 0:8a7c58553b44 | 437 | |
TheChrisyd | 0:8a7c58553b44 | 438 | static void hexDigit(byte b) |
TheChrisyd | 0:8a7c58553b44 | 439 | { |
TheChrisyd | 0:8a7c58553b44 | 440 | b = (b&0x0f)+'0'; |
TheChrisyd | 0:8a7c58553b44 | 441 | if (b > '9') { |
TheChrisyd | 0:8a7c58553b44 | 442 | b += 'a'-('9'+1); |
TheChrisyd | 0:8a7c58553b44 | 443 | } |
TheChrisyd | 0:8a7c58553b44 | 444 | spiutils.write(b); |
TheChrisyd | 0:8a7c58553b44 | 445 | } |
TheChrisyd | 0:8a7c58553b44 | 446 | static void hexPair(byte b) |
TheChrisyd | 0:8a7c58553b44 | 447 | { |
TheChrisyd | 0:8a7c58553b44 | 448 | hexDigit(b>>4); |
TheChrisyd | 0:8a7c58553b44 | 449 | hexDigit(b); |
TheChrisyd | 0:8a7c58553b44 | 450 | } |
TheChrisyd | 0:8a7c58553b44 | 451 | void showHexNumber(unsigned int n, byte x, byte y) |
TheChrisyd | 0:8a7c58553b44 | 452 | { |
TheChrisyd | 0:8a7c58553b44 | 453 | GD.__wstart((64*y)+x); |
TheChrisyd | 0:8a7c58553b44 | 454 | hexPair(highByte(n)); |
TheChrisyd | 0:8a7c58553b44 | 455 | hexPair(lowByte(n)); |
TheChrisyd | 0:8a7c58553b44 | 456 | GD.__end(); |
TheChrisyd | 0:8a7c58553b44 | 457 | } |
TheChrisyd | 0:8a7c58553b44 | 458 | void writeColor(int c) |
TheChrisyd | 0:8a7c58553b44 | 459 | { |
TheChrisyd | 0:8a7c58553b44 | 460 | // Colors are five bits - encode in base 32 |
TheChrisyd | 0:8a7c58553b44 | 461 | c = (c&31)+'0'; |
TheChrisyd | 0:8a7c58553b44 | 462 | if (c > '9') { |
TheChrisyd | 0:8a7c58553b44 | 463 | c += 'A'-('9'+1); |
TheChrisyd | 0:8a7c58553b44 | 464 | } |
TheChrisyd | 0:8a7c58553b44 | 465 | pcu.printf("%d", c); |
TheChrisyd | 0:8a7c58553b44 | 466 | } |
TheChrisyd | 0:8a7c58553b44 | 467 | void sendScreenshot() |
TheChrisyd | 0:8a7c58553b44 | 468 | { |
TheChrisyd | 0:8a7c58553b44 | 469 | pcu.baud(115200); |
TheChrisyd | 0:8a7c58553b44 | 470 | for (int i=0; i<300; ++i) { |
TheChrisyd | 0:8a7c58553b44 | 471 | // Ask for the line... |
TheChrisyd | 0:8a7c58553b44 | 472 | GD.wr16(SCREENSHOT_Y, 0x8000|i); |
TheChrisyd | 0:8a7c58553b44 | 473 | // Wait for it to appear |
TheChrisyd | 0:8a7c58553b44 | 474 | while ((GD.rd(SCREENSHOT_Y+1)&0x80)==0) { |
TheChrisyd | 0:8a7c58553b44 | 475 | delay(1); |
TheChrisyd | 0:8a7c58553b44 | 476 | } |
TheChrisyd | 0:8a7c58553b44 | 477 | // Send the line of pixels to the serial port |
TheChrisyd | 0:8a7c58553b44 | 478 | for (int x=0; x<400; ++x) { |
TheChrisyd | 0:8a7c58553b44 | 479 | uint16_t pixel = GD.rd16(SCREENSHOT+(x*2)); |
TheChrisyd | 0:8a7c58553b44 | 480 | writeColor(pixel>>10); // Red |
TheChrisyd | 0:8a7c58553b44 | 481 | writeColor(pixel>>5); // Green |
TheChrisyd | 0:8a7c58553b44 | 482 | writeColor(pixel); // Blue |
TheChrisyd | 0:8a7c58553b44 | 483 | } |
TheChrisyd | 0:8a7c58553b44 | 484 | pcu.printf("\n"); |
TheChrisyd | 0:8a7c58553b44 | 485 | } |
TheChrisyd | 0:8a7c58553b44 | 486 | // Restore sanity |
TheChrisyd | 0:8a7c58553b44 | 487 | GD.wr16(SCREENSHOT_Y, 0); |
TheChrisyd | 0:8a7c58553b44 | 488 | } |