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