Helios Lyons 201239214

Dependencies:   mbed

Committer:
helioslyons
Date:
Tue Apr 14 13:22:35 2020 +0000
Revision:
5:72f59786b695
Parent:
1:a3f43007030e
Import to Mbed Studio

Who changed what in which revision?

UserRevisionLine numberNew contents of line
helioslyons 1:a3f43007030e 1 #include "Gamepad.h"
helioslyons 1:a3f43007030e 2
helioslyons 1:a3f43007030e 3 #include "mbed.h"
helioslyons 1:a3f43007030e 4
helioslyons 1:a3f43007030e 5 //////////// constructor/destructor ////////////
helioslyons 1:a3f43007030e 6 Gamepad::Gamepad()
helioslyons 1:a3f43007030e 7 :
helioslyons 1:a3f43007030e 8 _led1(new PwmOut(PTA2)),
helioslyons 1:a3f43007030e 9 _led2(new PwmOut(PTC2)),
helioslyons 1:a3f43007030e 10 _led3(new PwmOut(PTC3)),
helioslyons 1:a3f43007030e 11 _led4(new PwmOut(PTA1)),
helioslyons 1:a3f43007030e 12 _led5(new PwmOut(PTC10)),
helioslyons 1:a3f43007030e 13 _led6(new PwmOut(PTC11)),
helioslyons 1:a3f43007030e 14
helioslyons 1:a3f43007030e 15 _button_A(new InterruptIn(PTC7)),
helioslyons 1:a3f43007030e 16 _button_B(new InterruptIn(PTC9)),
helioslyons 1:a3f43007030e 17 _button_X(new InterruptIn(PTC5)),
helioslyons 1:a3f43007030e 18 _button_Y(new InterruptIn(PTC0)),
helioslyons 1:a3f43007030e 19 _button_start(new InterruptIn(PTC8)),
helioslyons 1:a3f43007030e 20
helioslyons 1:a3f43007030e 21 _vert(new AnalogIn(PTB11)),
helioslyons 1:a3f43007030e 22 _horiz(new AnalogIn(PTB10)),
helioslyons 1:a3f43007030e 23
helioslyons 1:a3f43007030e 24 _pot1(new AnalogIn(PTB2)),
helioslyons 1:a3f43007030e 25 _pot2(new AnalogIn(PTB3)),
helioslyons 1:a3f43007030e 26
helioslyons 1:a3f43007030e 27 dac(new AnalogOut(DAC0_OUT)),
helioslyons 1:a3f43007030e 28 ticker(new Ticker),
helioslyons 1:a3f43007030e 29 timeout(new Timeout),
helioslyons 1:a3f43007030e 30 note_timeout(new Timeout),
helioslyons 1:a3f43007030e 31
helioslyons 1:a3f43007030e 32 _x0(0),
helioslyons 1:a3f43007030e 33 _y0(0)
helioslyons 1:a3f43007030e 34 {}
helioslyons 1:a3f43007030e 35
helioslyons 1:a3f43007030e 36
helioslyons 1:a3f43007030e 37 ///////////////// public methods /////////////////
helioslyons 1:a3f43007030e 38
helioslyons 1:a3f43007030e 39 void Gamepad::init()
helioslyons 1:a3f43007030e 40 {
helioslyons 1:a3f43007030e 41 leds_off();
helioslyons 1:a3f43007030e 42
helioslyons 1:a3f43007030e 43 // read centred values of joystick
helioslyons 1:a3f43007030e 44 _x0 = _horiz->read();
helioslyons 1:a3f43007030e 45 _y0 = _vert->read();
helioslyons 1:a3f43007030e 46
helioslyons 1:a3f43007030e 47 // Set all buttons to PullUp
helioslyons 1:a3f43007030e 48 _button_A->mode(PullUp);
helioslyons 1:a3f43007030e 49 _button_B->mode(PullUp);
helioslyons 1:a3f43007030e 50 _button_X->mode(PullUp);
helioslyons 1:a3f43007030e 51 _button_Y->mode(PullUp);
helioslyons 1:a3f43007030e 52 _button_start->mode(PullUp);
helioslyons 1:a3f43007030e 53
helioslyons 1:a3f43007030e 54 // Set up interrupts for the fall of buttons
helioslyons 1:a3f43007030e 55 _button_A->fall(callback(this,&Gamepad::A_fall_interrupt));
helioslyons 1:a3f43007030e 56 _button_B->fall(callback(this,&Gamepad::B_fall_interrupt));
helioslyons 1:a3f43007030e 57 _button_X->fall(callback(this,&Gamepad::X_fall_interrupt));
helioslyons 1:a3f43007030e 58 _button_Y->fall(callback(this,&Gamepad::Y_fall_interrupt));
helioslyons 1:a3f43007030e 59 _button_start->fall(callback(this,&Gamepad::start_fall_interrupt));
helioslyons 1:a3f43007030e 60
helioslyons 1:a3f43007030e 61 // initalise button flags
helioslyons 1:a3f43007030e 62 reset_buttons();
helioslyons 1:a3f43007030e 63
helioslyons 1:a3f43007030e 64 // number of samples
helioslyons 1:a3f43007030e 65 _n = 16;
helioslyons 1:a3f43007030e 66 _sample_array = new float[_n];
helioslyons 1:a3f43007030e 67
helioslyons 1:a3f43007030e 68 // create sample array for one period between 0.0 and 1.0
helioslyons 1:a3f43007030e 69 for (int i = 0; i < _n ; i++) {
helioslyons 1:a3f43007030e 70 _sample_array[i] = 0.5f + 0.5f*sin(i*2*PI/_n);
helioslyons 1:a3f43007030e 71 //printf("y[%i] = %f\n",i,_sample_array[i]);
helioslyons 1:a3f43007030e 72 }
helioslyons 1:a3f43007030e 73
helioslyons 1:a3f43007030e 74 }
helioslyons 1:a3f43007030e 75
helioslyons 1:a3f43007030e 76 void Gamepad::leds_off()
helioslyons 1:a3f43007030e 77 {
helioslyons 1:a3f43007030e 78 leds(0.0);
helioslyons 1:a3f43007030e 79 }
helioslyons 1:a3f43007030e 80
helioslyons 1:a3f43007030e 81 void Gamepad::leds_on()
helioslyons 1:a3f43007030e 82 {
helioslyons 1:a3f43007030e 83 leds(1.0);
helioslyons 1:a3f43007030e 84 }
helioslyons 1:a3f43007030e 85
helioslyons 1:a3f43007030e 86 void Gamepad::leds(float val) const
helioslyons 1:a3f43007030e 87 {
helioslyons 1:a3f43007030e 88 if (val < 0.0f) {
helioslyons 1:a3f43007030e 89 val = 0.0f;
helioslyons 1:a3f43007030e 90 }
helioslyons 1:a3f43007030e 91 if (val > 1.0f) {
helioslyons 1:a3f43007030e 92 val = 1.0f;
helioslyons 1:a3f43007030e 93 }
helioslyons 1:a3f43007030e 94
helioslyons 1:a3f43007030e 95 // leds are active-low, so subtract from 1.0
helioslyons 1:a3f43007030e 96 // 0.0 corresponds to fully-off, 1.0 to fully-on
helioslyons 1:a3f43007030e 97 val = 1.0f - val;
helioslyons 1:a3f43007030e 98
helioslyons 1:a3f43007030e 99 _led1->write(val);
helioslyons 1:a3f43007030e 100 _led2->write(val);
helioslyons 1:a3f43007030e 101 _led3->write(val);
helioslyons 1:a3f43007030e 102 _led4->write(val);
helioslyons 1:a3f43007030e 103 _led5->write(val);
helioslyons 1:a3f43007030e 104 _led6->write(val);
helioslyons 1:a3f43007030e 105 }
helioslyons 1:a3f43007030e 106
helioslyons 1:a3f43007030e 107 void Gamepad::led(int n,float val) const
helioslyons 1:a3f43007030e 108 {
helioslyons 1:a3f43007030e 109 // ensure they are within valid range
helioslyons 1:a3f43007030e 110 if (val < 0.0f) {
helioslyons 1:a3f43007030e 111 val = 0.0f;
helioslyons 1:a3f43007030e 112 }
helioslyons 1:a3f43007030e 113 if (val > 1.0f) {
helioslyons 1:a3f43007030e 114 val = 1.0f;
helioslyons 1:a3f43007030e 115 }
helioslyons 1:a3f43007030e 116
helioslyons 1:a3f43007030e 117 switch (n) {
helioslyons 1:a3f43007030e 118
helioslyons 1:a3f43007030e 119 // check for valid LED number and set value
helioslyons 1:a3f43007030e 120
helioslyons 1:a3f43007030e 121 case 1:
helioslyons 1:a3f43007030e 122 _led1->write(1.0f-val); // active-low so subtract from 1
helioslyons 1:a3f43007030e 123 break;
helioslyons 1:a3f43007030e 124 case 2:
helioslyons 1:a3f43007030e 125 _led2->write(1.0f-val); // active-low so subtract from 1
helioslyons 1:a3f43007030e 126 break;
helioslyons 1:a3f43007030e 127 case 3:
helioslyons 1:a3f43007030e 128 _led3->write(1.0f-val); // active-low so subtract from 1
helioslyons 1:a3f43007030e 129 break;
helioslyons 1:a3f43007030e 130 case 4:
helioslyons 1:a3f43007030e 131 _led4->write(1.0f-val); // active-low so subtract from 1
helioslyons 1:a3f43007030e 132 break;
helioslyons 1:a3f43007030e 133 case 5:
helioslyons 1:a3f43007030e 134 _led5->write(1.0f-val); // active-low so subtract from 1
helioslyons 1:a3f43007030e 135 break;
helioslyons 1:a3f43007030e 136 case 6:
helioslyons 1:a3f43007030e 137 _led6->write(1.0f-val); // active-low so subtract from 1
helioslyons 1:a3f43007030e 138 break;
helioslyons 1:a3f43007030e 139
helioslyons 1:a3f43007030e 140 }
helioslyons 1:a3f43007030e 141 }
helioslyons 1:a3f43007030e 142
helioslyons 1:a3f43007030e 143 float Gamepad::read_pot1() const
helioslyons 1:a3f43007030e 144 {
helioslyons 1:a3f43007030e 145 return _pot1->read();
helioslyons 1:a3f43007030e 146 }
helioslyons 1:a3f43007030e 147
helioslyons 1:a3f43007030e 148 float Gamepad::read_pot2() const
helioslyons 1:a3f43007030e 149 {
helioslyons 1:a3f43007030e 150 return _pot2->read();
helioslyons 1:a3f43007030e 151 }
helioslyons 1:a3f43007030e 152
helioslyons 1:a3f43007030e 153
helioslyons 1:a3f43007030e 154 // this method gets the magnitude of the joystick movement
helioslyons 1:a3f43007030e 155 float Gamepad::get_mag()
helioslyons 1:a3f43007030e 156 {
helioslyons 1:a3f43007030e 157 Polar p = get_polar();
helioslyons 1:a3f43007030e 158 return p.mag;
helioslyons 1:a3f43007030e 159 }
helioslyons 1:a3f43007030e 160
helioslyons 1:a3f43007030e 161 // this method gets the angle of joystick movement (0 to 360, 0 North)
helioslyons 1:a3f43007030e 162 float Gamepad::get_angle()
helioslyons 1:a3f43007030e 163 {
helioslyons 1:a3f43007030e 164 Polar p = get_polar();
helioslyons 1:a3f43007030e 165 return p.angle;
helioslyons 1:a3f43007030e 166 }
helioslyons 1:a3f43007030e 167
helioslyons 1:a3f43007030e 168 Direction Gamepad::get_direction()
helioslyons 1:a3f43007030e 169 {
helioslyons 1:a3f43007030e 170 float angle = get_angle(); // 0 to 360, -1 for centred
helioslyons 1:a3f43007030e 171
helioslyons 1:a3f43007030e 172 Direction d;
helioslyons 1:a3f43007030e 173 // partition 360 into segments and check which segment the angle is in
helioslyons 1:a3f43007030e 174 if (angle < 0.0f) {
helioslyons 1:a3f43007030e 175 d = CENTRE; // check for -1.0 angle
helioslyons 1:a3f43007030e 176 } else if (angle < 22.5f) { // then keep going in 45 degree increments
helioslyons 1:a3f43007030e 177 d = N;
helioslyons 1:a3f43007030e 178 } else if (angle < 67.5f) {
helioslyons 1:a3f43007030e 179 d = NE;
helioslyons 1:a3f43007030e 180 } else if (angle < 112.5f) {
helioslyons 1:a3f43007030e 181 d = E;
helioslyons 1:a3f43007030e 182 } else if (angle < 157.5f) {
helioslyons 1:a3f43007030e 183 d = SE;
helioslyons 1:a3f43007030e 184 } else if (angle < 202.5f) {
helioslyons 1:a3f43007030e 185 d = S;
helioslyons 1:a3f43007030e 186 } else if (angle < 247.5f) {
helioslyons 1:a3f43007030e 187 d = SW;
helioslyons 1:a3f43007030e 188 } else if (angle < 292.5f) {
helioslyons 1:a3f43007030e 189 d = W;
helioslyons 1:a3f43007030e 190 } else if (angle < 337.5f) {
helioslyons 1:a3f43007030e 191 d = NW;
helioslyons 1:a3f43007030e 192 } else {
helioslyons 1:a3f43007030e 193 d = N;
helioslyons 1:a3f43007030e 194 }
helioslyons 1:a3f43007030e 195
helioslyons 1:a3f43007030e 196 return d;
helioslyons 1:a3f43007030e 197 }
helioslyons 1:a3f43007030e 198
helioslyons 1:a3f43007030e 199 void Gamepad::reset_buttons()
helioslyons 1:a3f43007030e 200 {
helioslyons 1:a3f43007030e 201 A_fall = B_fall = X_fall = Y_fall = start_fall = false;
helioslyons 1:a3f43007030e 202 }
helioslyons 1:a3f43007030e 203
helioslyons 1:a3f43007030e 204 bool Gamepad::A_pressed()
helioslyons 1:a3f43007030e 205 {
helioslyons 1:a3f43007030e 206 if (A_fall) {
helioslyons 1:a3f43007030e 207 A_fall = false;
helioslyons 1:a3f43007030e 208 return true;
helioslyons 1:a3f43007030e 209 } else {
helioslyons 1:a3f43007030e 210 return false;
helioslyons 1:a3f43007030e 211 }
helioslyons 1:a3f43007030e 212 }
helioslyons 1:a3f43007030e 213
helioslyons 1:a3f43007030e 214 bool Gamepad::B_pressed()
helioslyons 1:a3f43007030e 215 {
helioslyons 1:a3f43007030e 216 if (B_fall) {
helioslyons 1:a3f43007030e 217 B_fall = false;
helioslyons 1:a3f43007030e 218 return true;
helioslyons 1:a3f43007030e 219 } else {
helioslyons 1:a3f43007030e 220 return false;
helioslyons 1:a3f43007030e 221 }
helioslyons 1:a3f43007030e 222 }
helioslyons 1:a3f43007030e 223
helioslyons 1:a3f43007030e 224 bool Gamepad::X_pressed()
helioslyons 1:a3f43007030e 225 {
helioslyons 1:a3f43007030e 226 if (X_fall) {
helioslyons 1:a3f43007030e 227 X_fall = false;
helioslyons 1:a3f43007030e 228 return true;
helioslyons 1:a3f43007030e 229 } else {
helioslyons 1:a3f43007030e 230 return false;
helioslyons 1:a3f43007030e 231 }
helioslyons 1:a3f43007030e 232 }
helioslyons 1:a3f43007030e 233
helioslyons 1:a3f43007030e 234 bool Gamepad::Y_pressed()
helioslyons 1:a3f43007030e 235 {
helioslyons 1:a3f43007030e 236 if (Y_fall) {
helioslyons 1:a3f43007030e 237 Y_fall = false;
helioslyons 1:a3f43007030e 238 return true;
helioslyons 1:a3f43007030e 239 } else {
helioslyons 1:a3f43007030e 240 return false;
helioslyons 1:a3f43007030e 241 }
helioslyons 1:a3f43007030e 242 }
helioslyons 1:a3f43007030e 243
helioslyons 1:a3f43007030e 244 bool Gamepad::start_pressed()
helioslyons 1:a3f43007030e 245 {
helioslyons 1:a3f43007030e 246 if (start_fall) {
helioslyons 1:a3f43007030e 247 start_fall = false;
helioslyons 1:a3f43007030e 248 return true;
helioslyons 1:a3f43007030e 249 } else {
helioslyons 1:a3f43007030e 250 return false;
helioslyons 1:a3f43007030e 251 }
helioslyons 1:a3f43007030e 252 }
helioslyons 1:a3f43007030e 253
helioslyons 1:a3f43007030e 254 bool Gamepad::A_held()
helioslyons 1:a3f43007030e 255 {
helioslyons 1:a3f43007030e 256 // Buttons are configured as PullUp hence the not
helioslyons 1:a3f43007030e 257 return !_button_A->read();
helioslyons 1:a3f43007030e 258 }
helioslyons 1:a3f43007030e 259
helioslyons 1:a3f43007030e 260 bool Gamepad::B_held()
helioslyons 1:a3f43007030e 261 {
helioslyons 1:a3f43007030e 262 return !_button_B->read();
helioslyons 1:a3f43007030e 263 }
helioslyons 1:a3f43007030e 264
helioslyons 1:a3f43007030e 265 bool Gamepad::X_held()
helioslyons 1:a3f43007030e 266 {
helioslyons 1:a3f43007030e 267 return !_button_X->read();
helioslyons 1:a3f43007030e 268 }
helioslyons 1:a3f43007030e 269
helioslyons 1:a3f43007030e 270 bool Gamepad::Y_held()
helioslyons 1:a3f43007030e 271 {
helioslyons 1:a3f43007030e 272 return !_button_Y->read();
helioslyons 1:a3f43007030e 273 }
helioslyons 1:a3f43007030e 274
helioslyons 1:a3f43007030e 275 bool Gamepad::start_held()
helioslyons 1:a3f43007030e 276 {
helioslyons 1:a3f43007030e 277 return !_button_start->read();
helioslyons 1:a3f43007030e 278 }
helioslyons 1:a3f43007030e 279
helioslyons 1:a3f43007030e 280 ///////////////////// private methods ////////////////////////
helioslyons 1:a3f43007030e 281
helioslyons 1:a3f43007030e 282 // get raw joystick coordinate in range -1 to 1
helioslyons 1:a3f43007030e 283 // Direction (x,y)
helioslyons 1:a3f43007030e 284 // North (0,1)
helioslyons 1:a3f43007030e 285 // East (1,0)
helioslyons 1:a3f43007030e 286 // South (0,-1)
helioslyons 1:a3f43007030e 287 // West (-1,0)
helioslyons 1:a3f43007030e 288 Vector2D Gamepad::get_coord()
helioslyons 1:a3f43007030e 289 {
helioslyons 1:a3f43007030e 290 // read() returns value in range 0.0 to 1.0 so is scaled and centre value
helioslyons 1:a3f43007030e 291 // substracted to get values in the range -1.0 to 1.0
helioslyons 1:a3f43007030e 292 float x = 2.0f*( _horiz->read() - _x0 );
helioslyons 1:a3f43007030e 293 float y = 2.0f*( _vert->read() - _y0 );
helioslyons 1:a3f43007030e 294
helioslyons 1:a3f43007030e 295 // Note: the y value here is inverted to ensure the positive y is up
helioslyons 1:a3f43007030e 296
helioslyons 1:a3f43007030e 297 Vector2D coord = {x,-y};
helioslyons 1:a3f43007030e 298 return coord;
helioslyons 1:a3f43007030e 299 }
helioslyons 1:a3f43007030e 300
helioslyons 1:a3f43007030e 301 // This maps the raw x,y coord onto a circular grid.
helioslyons 1:a3f43007030e 302 // See: http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html
helioslyons 1:a3f43007030e 303 Vector2D Gamepad::get_mapped_coord()
helioslyons 1:a3f43007030e 304 {
helioslyons 1:a3f43007030e 305 Vector2D coord = get_coord();
helioslyons 1:a3f43007030e 306
helioslyons 1:a3f43007030e 307 // do the transformation
helioslyons 1:a3f43007030e 308 float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f);
helioslyons 1:a3f43007030e 309 float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f);
helioslyons 1:a3f43007030e 310
helioslyons 1:a3f43007030e 311 Vector2D mapped_coord = {x,y};
helioslyons 1:a3f43007030e 312 return mapped_coord;
helioslyons 1:a3f43007030e 313 }
helioslyons 1:a3f43007030e 314
helioslyons 1:a3f43007030e 315 // this function converts the mapped coordinates into polar form
helioslyons 1:a3f43007030e 316 Polar Gamepad::get_polar()
helioslyons 1:a3f43007030e 317 {
helioslyons 1:a3f43007030e 318 // get the mapped coordinate
helioslyons 1:a3f43007030e 319 Vector2D coord = get_mapped_coord();
helioslyons 1:a3f43007030e 320
helioslyons 1:a3f43007030e 321 // at this point, 0 degrees (i.e. x-axis) will be defined to the East.
helioslyons 1:a3f43007030e 322 // We want 0 degrees to correspond to North and increase clockwise to 359
helioslyons 1:a3f43007030e 323 // like a compass heading, so we need to swap the axis and invert y
helioslyons 1:a3f43007030e 324 float x = coord.y;
helioslyons 1:a3f43007030e 325 float y = coord.x;
helioslyons 1:a3f43007030e 326
helioslyons 1:a3f43007030e 327 float mag = sqrt(x*x+y*y); // pythagoras
helioslyons 1:a3f43007030e 328 float angle = RAD2DEG*atan2(y,x);
helioslyons 1:a3f43007030e 329 // angle will be in range -180 to 180, so add 360 to negative angles to
helioslyons 1:a3f43007030e 330 // move to 0 to 360 range
helioslyons 1:a3f43007030e 331 if (angle < 0.0f) {
helioslyons 1:a3f43007030e 332 angle+=360.0f;
helioslyons 1:a3f43007030e 333 }
helioslyons 1:a3f43007030e 334
helioslyons 1:a3f43007030e 335 // the noise on the ADC causes the values of x and y to fluctuate slightly
helioslyons 1:a3f43007030e 336 // around the centred values. This causes the random angle values to get
helioslyons 1:a3f43007030e 337 // calculated when the joystick is centred and untouched. This is also when
helioslyons 1:a3f43007030e 338 // the magnitude is very small, so we can check for a small magnitude and then
helioslyons 1:a3f43007030e 339 // set the angle to -1. This will inform us when the angle is invalid and the
helioslyons 1:a3f43007030e 340 // joystick is centred
helioslyons 1:a3f43007030e 341
helioslyons 1:a3f43007030e 342 if (mag < TOL) {
helioslyons 1:a3f43007030e 343 mag = 0.0f;
helioslyons 1:a3f43007030e 344 angle = -1.0f;
helioslyons 1:a3f43007030e 345 }
helioslyons 1:a3f43007030e 346
helioslyons 1:a3f43007030e 347 Polar p = {mag,angle};
helioslyons 1:a3f43007030e 348 return p;
helioslyons 1:a3f43007030e 349 }
helioslyons 1:a3f43007030e 350
helioslyons 1:a3f43007030e 351 // ISRs for buttons
helioslyons 1:a3f43007030e 352 void Gamepad::A_fall_interrupt()
helioslyons 1:a3f43007030e 353 {
helioslyons 1:a3f43007030e 354 A_fall = true;
helioslyons 1:a3f43007030e 355 }
helioslyons 1:a3f43007030e 356 void Gamepad::B_fall_interrupt()
helioslyons 1:a3f43007030e 357 {
helioslyons 1:a3f43007030e 358 B_fall = true;
helioslyons 1:a3f43007030e 359 }
helioslyons 1:a3f43007030e 360 void Gamepad::X_fall_interrupt()
helioslyons 1:a3f43007030e 361 {
helioslyons 1:a3f43007030e 362 X_fall = true;
helioslyons 1:a3f43007030e 363 }
helioslyons 1:a3f43007030e 364 void Gamepad::Y_fall_interrupt()
helioslyons 1:a3f43007030e 365 {
helioslyons 1:a3f43007030e 366 Y_fall = true;
helioslyons 1:a3f43007030e 367 }
helioslyons 1:a3f43007030e 368 void Gamepad::start_fall_interrupt()
helioslyons 1:a3f43007030e 369 {
helioslyons 1:a3f43007030e 370 start_fall = true;
helioslyons 1:a3f43007030e 371 }
helioslyons 1:a3f43007030e 372
helioslyons 1:a3f43007030e 373 void Gamepad::set_bpm(float bpm)
helioslyons 1:a3f43007030e 374 {
helioslyons 1:a3f43007030e 375 _bpm = bpm;
helioslyons 1:a3f43007030e 376 }
helioslyons 1:a3f43007030e 377
helioslyons 1:a3f43007030e 378 void Gamepad::tone(float frequency,float duration)
helioslyons 1:a3f43007030e 379 {
helioslyons 1:a3f43007030e 380 // calculate time step between samples
helioslyons 1:a3f43007030e 381 float dt = 1.0f/(frequency*_n);
helioslyons 1:a3f43007030e 382 // start from beginning of LUT
helioslyons 1:a3f43007030e 383 _sample = 0;
helioslyons 1:a3f43007030e 384
helioslyons 1:a3f43007030e 385 // setup ticker and timeout to stop ticker
helioslyons 1:a3f43007030e 386
helioslyons 1:a3f43007030e 387 // the ticker repeats every dt to plat each sample in turn
helioslyons 1:a3f43007030e 388 ticker->attach(callback(this, &Gamepad::ticker_isr), dt);
helioslyons 1:a3f43007030e 389 // the timeout stops the ticker after the required duration
helioslyons 1:a3f43007030e 390 timeout->attach(callback(this, &Gamepad::timeout_isr), duration );
helioslyons 1:a3f43007030e 391 }
helioslyons 1:a3f43007030e 392
helioslyons 1:a3f43007030e 393 void Gamepad::play_melody(int length,const int *notes,const int *durations,float bpm,bool repeat)
helioslyons 1:a3f43007030e 394 {
helioslyons 1:a3f43007030e 395 // copy arguments to member variables
helioslyons 1:a3f43007030e 396 _bpm = bpm;
helioslyons 1:a3f43007030e 397 _notes = notes; // pointer for array
helioslyons 1:a3f43007030e 398 _durations = durations; // pointer for array
helioslyons 1:a3f43007030e 399 _melody_length = length;
helioslyons 1:a3f43007030e 400 _repeat = repeat;
helioslyons 1:a3f43007030e 401
helioslyons 1:a3f43007030e 402 _note = 0; // start from first note
helioslyons 1:a3f43007030e 403
helioslyons 1:a3f43007030e 404 play_next_note(); // play the next note in the melody
helioslyons 1:a3f43007030e 405 }
helioslyons 1:a3f43007030e 406
helioslyons 1:a3f43007030e 407 void Gamepad::write_dac(float val)
helioslyons 1:a3f43007030e 408 {
helioslyons 1:a3f43007030e 409 if (val < 0.0f) {
helioslyons 1:a3f43007030e 410 val = 0.0f;
helioslyons 1:a3f43007030e 411 } else if (val > 1.0f) {
helioslyons 1:a3f43007030e 412 val = 1.0f;
helioslyons 1:a3f43007030e 413 }
helioslyons 1:a3f43007030e 414 dac->write(val);
helioslyons 1:a3f43007030e 415 }
helioslyons 1:a3f43007030e 416
helioslyons 1:a3f43007030e 417
helioslyons 1:a3f43007030e 418 void Gamepad::play_next_note()
helioslyons 1:a3f43007030e 419 {
helioslyons 1:a3f43007030e 420 // _note is the note index to play
helioslyons 1:a3f43007030e 421
helioslyons 1:a3f43007030e 422 // calculate the duration and frequency of the note
helioslyons 1:a3f43007030e 423 float duration = 60.0f/(_bpm*_durations[_note]);
helioslyons 1:a3f43007030e 424 float frequency = float(_notes[_note]);
helioslyons 1:a3f43007030e 425 //printf("[%i] f = %f d = %f\n",_note,frequency,duration);
helioslyons 1:a3f43007030e 426
helioslyons 1:a3f43007030e 427 // check if the note is not a space and if not then play the note
helioslyons 1:a3f43007030e 428 if (frequency > 0) {
helioslyons 1:a3f43007030e 429 tone(frequency,duration);
helioslyons 1:a3f43007030e 430 }
helioslyons 1:a3f43007030e 431
helioslyons 1:a3f43007030e 432 // the timeout goes to the next note in the melody
helioslyons 1:a3f43007030e 433 // double the duration to leave a bit of a gap in between notes to be better
helioslyons 1:a3f43007030e 434 // able to distinguish them
helioslyons 1:a3f43007030e 435 note_timeout->attach(callback(this, &Gamepad::note_timeout_isr), duration*2.0f );
helioslyons 1:a3f43007030e 436 }
helioslyons 1:a3f43007030e 437
helioslyons 1:a3f43007030e 438 // called when the next note needs playing
helioslyons 1:a3f43007030e 439 void Gamepad::note_timeout_isr()
helioslyons 1:a3f43007030e 440 {
helioslyons 1:a3f43007030e 441 _note++; // go onto next note
helioslyons 1:a3f43007030e 442
helioslyons 1:a3f43007030e 443 // if in repeat mode then reset the note counter when get to end of melody
helioslyons 1:a3f43007030e 444 if (_repeat && _note == _melody_length) {
helioslyons 1:a3f43007030e 445 _note=0;
helioslyons 1:a3f43007030e 446 }
helioslyons 1:a3f43007030e 447
helioslyons 1:a3f43007030e 448 // check if note is within the melody
helioslyons 1:a3f43007030e 449 if (_note < _melody_length) {
helioslyons 1:a3f43007030e 450 play_next_note();
helioslyons 1:a3f43007030e 451 }
helioslyons 1:a3f43007030e 452 }
helioslyons 1:a3f43007030e 453
helioslyons 1:a3f43007030e 454 void Gamepad::ticker_isr()
helioslyons 1:a3f43007030e 455 {
helioslyons 1:a3f43007030e 456 dac->write(_sample_array[_sample%_n]); // use modulo to get index to play
helioslyons 1:a3f43007030e 457 _sample++; // increment the sample ready for next time
helioslyons 1:a3f43007030e 458 }
helioslyons 1:a3f43007030e 459
helioslyons 1:a3f43007030e 460 void Gamepad::timeout_isr()
helioslyons 1:a3f43007030e 461 {
helioslyons 1:a3f43007030e 462 // stops the ticker to end the note
helioslyons 1:a3f43007030e 463 ticker->detach();
helioslyons 1:a3f43007030e 464 }