EmbedEd
/
mbed_theremin
xypad theremin for LPC1768
note.cpp@2:c5eeaf1c8e69, 2016-03-14 (annotated)
- Committer:
- exopiped
- Date:
- Mon Mar 14 23:43:44 2016 +0000
- Revision:
- 2:c5eeaf1c8e69
- Parent:
- 1:aa184d2eb2e3
touch screen driver glitches removed; debug statements commented out
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
exopiped | 0:8ee38453bad9 | 1 | /* |
exopiped | 0:8ee38453bad9 | 2 | * note.cpp -- manage production of notes in response to |
exopiped | 0:8ee38453bad9 | 3 | * touch screen input |
exopiped | 0:8ee38453bad9 | 4 | */ |
exopiped | 0:8ee38453bad9 | 5 | #include "mbed.h" |
exopiped | 0:8ee38453bad9 | 6 | #include "InterruptIn.h" |
exopiped | 0:8ee38453bad9 | 7 | #include "debug.h" |
exopiped | 0:8ee38453bad9 | 8 | #include "dma.h" |
exopiped | 0:8ee38453bad9 | 9 | #include "envlp.h" |
exopiped | 0:8ee38453bad9 | 10 | #include "wave.h" |
exopiped | 0:8ee38453bad9 | 11 | #include "touch.h" |
exopiped | 0:8ee38453bad9 | 12 | #include "jswitch.h" |
exopiped | 0:8ee38453bad9 | 13 | #include "note.h" |
exopiped | 0:8ee38453bad9 | 14 | |
exopiped | 1:aa184d2eb2e3 | 15 | #define TURN_DMA_OFF_AFTER_EACH_NOTE 0 |
exopiped | 0:8ee38453bad9 | 16 | |
exopiped | 0:8ee38453bad9 | 17 | typedef enum {NOTE_ATTACK,NOTE_DECAY,NOTE_SUSTAIN,NOTE_RELEASE,NOTE_OFF} NOTE_STATE; |
exopiped | 0:8ee38453bad9 | 18 | |
exopiped | 0:8ee38453bad9 | 19 | static void note_start(void); |
exopiped | 0:8ee38453bad9 | 20 | static void note_state_machine(void); |
exopiped | 0:8ee38453bad9 | 21 | static void note_fill_buf(void); |
exopiped | 0:8ee38453bad9 | 22 | static void note_attack(void); |
exopiped | 0:8ee38453bad9 | 23 | static bool note_attack_done(void); |
exopiped | 0:8ee38453bad9 | 24 | static bool note_decay_done(void); |
exopiped | 0:8ee38453bad9 | 25 | static void note_release(void); |
exopiped | 0:8ee38453bad9 | 26 | static bool note_release_done(void); |
exopiped | 0:8ee38453bad9 | 27 | static bool note_released(void); |
exopiped | 0:8ee38453bad9 | 28 | static void note_end(void); |
exopiped | 0:8ee38453bad9 | 29 | |
exopiped | 0:8ee38453bad9 | 30 | static unsigned note_freq=0; // frequency in Hz |
exopiped | 0:8ee38453bad9 | 31 | static NOTE_STATE note_state=NOTE_OFF; |
exopiped | 0:8ee38453bad9 | 32 | static int note_bufno= NIL; // NIL or index of dma buffer |
exopiped | 0:8ee38453bad9 | 33 | static int note_attack_bufcount; |
exopiped | 0:8ee38453bad9 | 34 | static int note_attack_delta; |
exopiped | 0:8ee38453bad9 | 35 | static int note_attack_bufs; |
exopiped | 0:8ee38453bad9 | 36 | static int note_decay_bufs; |
exopiped | 0:8ee38453bad9 | 37 | static int note_decay_bufcount; |
exopiped | 0:8ee38453bad9 | 38 | static int note_decay_delta; |
exopiped | 0:8ee38453bad9 | 39 | static int note_release_delta; |
exopiped | 0:8ee38453bad9 | 40 | static int note_first_bufval; |
exopiped | 0:8ee38453bad9 | 41 | static int note_last_bufval; |
exopiped | 0:8ee38453bad9 | 42 | static int note_release_numerator; |
exopiped | 0:8ee38453bad9 | 43 | static int note_release_denominator; |
exopiped | 0:8ee38453bad9 | 44 | |
exopiped | 0:8ee38453bad9 | 45 | void note_init(void) |
exopiped | 0:8ee38453bad9 | 46 | { |
exopiped | 0:8ee38453bad9 | 47 | note_freq = 0; |
exopiped | 0:8ee38453bad9 | 48 | note_state = NOTE_OFF; |
exopiped | 0:8ee38453bad9 | 49 | note_bufno = NIL; |
exopiped | 0:8ee38453bad9 | 50 | note_attack_bufcount=0; |
exopiped | 0:8ee38453bad9 | 51 | note_decay_bufcount=0; |
exopiped | 0:8ee38453bad9 | 52 | dma_init(); |
exopiped | 0:8ee38453bad9 | 53 | } |
exopiped | 0:8ee38453bad9 | 54 | |
exopiped | 0:8ee38453bad9 | 55 | void note_start(void) |
exopiped | 0:8ee38453bad9 | 56 | { |
exopiped | 0:8ee38453bad9 | 57 | if (wave_type_changed()) { |
exopiped | 0:8ee38453bad9 | 58 | wave_type_incr(); |
exopiped | 0:8ee38453bad9 | 59 | } |
exopiped | 0:8ee38453bad9 | 60 | wave_reset(); |
exopiped | 0:8ee38453bad9 | 61 | note_freq = touch_frequency(); |
exopiped | 0:8ee38453bad9 | 62 | note_attack_bufs=envlp_get_attack_bufs(); |
exopiped | 0:8ee38453bad9 | 63 | note_decay_bufs=envlp_get_decay_bufs(); |
exopiped | 0:8ee38453bad9 | 64 | note_release_delta = envlp_get_release_delta(); |
exopiped | 0:8ee38453bad9 | 65 | note_release_numerator = ENVLP_MAX - note_release_delta; |
exopiped | 0:8ee38453bad9 | 66 | note_release_denominator = ENVLP_MAX; |
exopiped | 0:8ee38453bad9 | 67 | // fill first two buffers |
exopiped | 0:8ee38453bad9 | 68 | note_attack(); |
exopiped | 0:8ee38453bad9 | 69 | note_set_bufno(0); |
exopiped | 0:8ee38453bad9 | 70 | note_state_machine(); |
exopiped | 0:8ee38453bad9 | 71 | note_fill_buf(); |
exopiped | 0:8ee38453bad9 | 72 | note_set_bufno(1); |
exopiped | 0:8ee38453bad9 | 73 | note_state_machine(); |
exopiped | 0:8ee38453bad9 | 74 | note_fill_buf(); |
exopiped | 1:aa184d2eb2e3 | 75 | note_bufno=NIL; |
exopiped | 0:8ee38453bad9 | 76 | dma_enable(); |
exopiped | 0:8ee38453bad9 | 77 | } |
exopiped | 0:8ee38453bad9 | 78 | |
exopiped | 0:8ee38453bad9 | 79 | void note_end(void) |
exopiped | 0:8ee38453bad9 | 80 | { |
exopiped | 0:8ee38453bad9 | 81 | dma_disable(); |
exopiped | 0:8ee38453bad9 | 82 | note_state=NOTE_OFF; |
exopiped | 1:aa184d2eb2e3 | 83 | note_bufno=NIL; |
exopiped | 0:8ee38453bad9 | 84 | } |
exopiped | 0:8ee38453bad9 | 85 | |
exopiped | 0:8ee38453bad9 | 86 | /* |
exopiped | 0:8ee38453bad9 | 87 | * note_update |
exopiped | 0:8ee38453bad9 | 88 | * update the frequency and attenuation factor for the |
exopiped | 0:8ee38453bad9 | 89 | * current note. If the current envelope first and last |
exopiped | 0:8ee38453bad9 | 90 | * add up to less than 2, end the note. |
exopiped | 0:8ee38453bad9 | 91 | * otherwise check to see if it is time to fill a dma buffer. |
exopiped | 0:8ee38453bad9 | 92 | * if so fill the one specified by note_fillbuf. |
exopiped | 0:8ee38453bad9 | 93 | */ |
exopiped | 0:8ee38453bad9 | 94 | |
exopiped | 0:8ee38453bad9 | 95 | void note_update(void) |
exopiped | 0:8ee38453bad9 | 96 | { |
exopiped | 0:8ee38453bad9 | 97 | // execute note state machine |
exopiped | 0:8ee38453bad9 | 98 | note_state_machine(); |
exopiped | 0:8ee38453bad9 | 99 | if(note_bufno!=NIL) { |
exopiped | 1:aa184d2eb2e3 | 100 | note_fill_buf(); |
exopiped | 0:8ee38453bad9 | 101 | } |
exopiped | 0:8ee38453bad9 | 102 | |
exopiped | 0:8ee38453bad9 | 103 | // handle presence or absence of touch |
exopiped | 0:8ee38453bad9 | 104 | if (touch_debounce()) { |
exopiped | 0:8ee38453bad9 | 105 | wait_ms(10); // wait 10 msec if touch present |
exopiped | 0:8ee38453bad9 | 106 | if (note_released() || !note_active()) { |
exopiped | 0:8ee38453bad9 | 107 | note_start(); |
exopiped | 0:8ee38453bad9 | 108 | } |
exopiped | 0:8ee38453bad9 | 109 | } else { |
exopiped | 0:8ee38453bad9 | 110 | if (note_active()) { |
exopiped | 0:8ee38453bad9 | 111 | if (!note_released()) { |
exopiped | 0:8ee38453bad9 | 112 | note_release(); |
exopiped | 0:8ee38453bad9 | 113 | } |
exopiped | 0:8ee38453bad9 | 114 | } |
exopiped | 0:8ee38453bad9 | 115 | } |
exopiped | 0:8ee38453bad9 | 116 | } |
exopiped | 0:8ee38453bad9 | 117 | |
exopiped | 0:8ee38453bad9 | 118 | void note_state_machine(void) |
exopiped | 0:8ee38453bad9 | 119 | { |
exopiped | 0:8ee38453bad9 | 120 | // execute state machine that manages envelope |
exopiped | 0:8ee38453bad9 | 121 | |
exopiped | 0:8ee38453bad9 | 122 | switch (note_state) { |
exopiped | 0:8ee38453bad9 | 123 | case NOTE_ATTACK: |
exopiped | 0:8ee38453bad9 | 124 | if (note_attack_done()) { |
exopiped | 0:8ee38453bad9 | 125 | note_state = NOTE_DECAY; |
exopiped | 0:8ee38453bad9 | 126 | } |
exopiped | 0:8ee38453bad9 | 127 | note_freq = touch_frequency(); |
exopiped | 0:8ee38453bad9 | 128 | break; |
exopiped | 0:8ee38453bad9 | 129 | |
exopiped | 0:8ee38453bad9 | 130 | case NOTE_DECAY: |
exopiped | 0:8ee38453bad9 | 131 | if(note_decay_done()) { |
exopiped | 0:8ee38453bad9 | 132 | note_state = NOTE_SUSTAIN; |
exopiped | 0:8ee38453bad9 | 133 | } |
exopiped | 0:8ee38453bad9 | 134 | note_freq = touch_frequency(); |
exopiped | 0:8ee38453bad9 | 135 | break; |
exopiped | 0:8ee38453bad9 | 136 | |
exopiped | 0:8ee38453bad9 | 137 | case NOTE_SUSTAIN: |
exopiped | 0:8ee38453bad9 | 138 | note_freq = touch_frequency(); |
exopiped | 0:8ee38453bad9 | 139 | break; |
exopiped | 0:8ee38453bad9 | 140 | |
exopiped | 0:8ee38453bad9 | 141 | case NOTE_RELEASE: |
exopiped | 0:8ee38453bad9 | 142 | if (note_release_done()) { |
exopiped | 0:8ee38453bad9 | 143 | note_end(); |
exopiped | 0:8ee38453bad9 | 144 | break; |
exopiped | 0:8ee38453bad9 | 145 | } |
exopiped | 0:8ee38453bad9 | 146 | break; |
exopiped | 0:8ee38453bad9 | 147 | case NOTE_OFF: |
exopiped | 0:8ee38453bad9 | 148 | default: |
exopiped | 0:8ee38453bad9 | 149 | break; |
exopiped | 0:8ee38453bad9 | 150 | } |
exopiped | 0:8ee38453bad9 | 151 | } |
exopiped | 0:8ee38453bad9 | 152 | |
exopiped | 0:8ee38453bad9 | 153 | /* |
exopiped | 0:8ee38453bad9 | 154 | * note_fill_buf |
exopiped | 0:8ee38453bad9 | 155 | * Use the first and last buffer envelope values, and the |
exopiped | 0:8ee38453bad9 | 156 | * wave values returned by wave_nextval() to compute the |
exopiped | 0:8ee38453bad9 | 157 | * envelop-modified wave values, and then apply the changes |
exopiped | 0:8ee38453bad9 | 158 | * necessary to output the values to the DAC data register. |
exopiped | 0:8ee38453bad9 | 159 | */ |
exopiped | 0:8ee38453bad9 | 160 | void note_fill_buf(void) |
exopiped | 0:8ee38453bad9 | 161 | { |
exopiped | 0:8ee38453bad9 | 162 | int j,start_env,end_env,env_val,wave_val,buf_val,amplitude; |
exopiped | 1:aa184d2eb2e3 | 163 | int *bufptr; |
exopiped | 0:8ee38453bad9 | 164 | |
exopiped | 0:8ee38453bad9 | 165 | bufptr = dma_get_bufptr(note_bufno); |
exopiped | 0:8ee38453bad9 | 166 | start_env = note_first_bufval; |
exopiped | 0:8ee38453bad9 | 167 | end_env = note_last_bufval; |
exopiped | 1:aa184d2eb2e3 | 168 | amplitude = touch_amplitude(); |
exopiped | 0:8ee38453bad9 | 169 | |
exopiped | 0:8ee38453bad9 | 170 | for (j=0;j<DMA_BUFSIZE;j++) { |
exopiped | 1:aa184d2eb2e3 | 171 | env_val=start_env+(end_env - start_env)*j/DMA_BUFSIZE; |
exopiped | 1:aa184d2eb2e3 | 172 | wave_val = wave_nextval(note_freq); |
exopiped | 1:aa184d2eb2e3 | 173 | buf_val = wave_val * env_val / ENVLP_MAX; |
exopiped | 1:aa184d2eb2e3 | 174 | buf_val=amplitude*buf_val/TOUCH_MAX_AMPLITUDE; |
exopiped | 1:aa184d2eb2e3 | 175 | bufptr[j]= DAC_POWER_MODE | ((buf_val << 6) & 0xFFC0); |
exopiped | 0:8ee38453bad9 | 176 | } |
exopiped | 1:aa184d2eb2e3 | 177 | |
exopiped | 1:aa184d2eb2e3 | 178 | note_bufno = NIL; |
exopiped | 0:8ee38453bad9 | 179 | switch (note_state) { |
exopiped | 0:8ee38453bad9 | 180 | case NOTE_ATTACK: |
exopiped | 0:8ee38453bad9 | 181 | note_attack_bufcount++; |
exopiped | 0:8ee38453bad9 | 182 | break; |
exopiped | 0:8ee38453bad9 | 183 | case NOTE_DECAY: |
exopiped | 0:8ee38453bad9 | 184 | note_decay_bufcount++; |
exopiped | 0:8ee38453bad9 | 185 | break; |
exopiped | 1:aa184d2eb2e3 | 186 | case NOTE_SUSTAIN: |
exopiped | 1:aa184d2eb2e3 | 187 | note_first_bufval = note_last_bufval; |
exopiped | 1:aa184d2eb2e3 | 188 | break; |
exopiped | 0:8ee38453bad9 | 189 | case NOTE_RELEASE: |
exopiped | 0:8ee38453bad9 | 190 | note_first_bufval = note_last_bufval; |
exopiped | 0:8ee38453bad9 | 191 | note_last_bufval = |
exopiped | 0:8ee38453bad9 | 192 | note_first_bufval * note_release_numerator |
exopiped | 0:8ee38453bad9 | 193 | / note_release_denominator; |
exopiped | 0:8ee38453bad9 | 194 | break; |
exopiped | 0:8ee38453bad9 | 195 | case NOTE_OFF: |
exopiped | 0:8ee38453bad9 | 196 | default: |
exopiped | 0:8ee38453bad9 | 197 | ; |
exopiped | 0:8ee38453bad9 | 198 | } |
exopiped | 0:8ee38453bad9 | 199 | } |
exopiped | 0:8ee38453bad9 | 200 | |
exopiped | 0:8ee38453bad9 | 201 | /* |
exopiped | 0:8ee38453bad9 | 202 | * note_release |
exopiped | 0:8ee38453bad9 | 203 | * touch has been lifted, note begins to decay |
exopiped | 0:8ee38453bad9 | 204 | */ |
exopiped | 0:8ee38453bad9 | 205 | void note_release(void) |
exopiped | 0:8ee38453bad9 | 206 | { |
exopiped | 0:8ee38453bad9 | 207 | note_state = NOTE_RELEASE; |
exopiped | 0:8ee38453bad9 | 208 | } |
exopiped | 0:8ee38453bad9 | 209 | /* |
exopiped | 0:8ee38453bad9 | 210 | * note_released |
exopiped | 0:8ee38453bad9 | 211 | * return true if note has been released |
exopiped | 0:8ee38453bad9 | 212 | * but not yet ended |
exopiped | 0:8ee38453bad9 | 213 | */ |
exopiped | 0:8ee38453bad9 | 214 | bool note_released(void) |
exopiped | 0:8ee38453bad9 | 215 | { |
exopiped | 0:8ee38453bad9 | 216 | return (note_state == NOTE_RELEASE); |
exopiped | 0:8ee38453bad9 | 217 | } |
exopiped | 0:8ee38453bad9 | 218 | bool note_active(void) |
exopiped | 0:8ee38453bad9 | 219 | { |
exopiped | 0:8ee38453bad9 | 220 | return (note_state < NOTE_OFF); |
exopiped | 0:8ee38453bad9 | 221 | } |
exopiped | 0:8ee38453bad9 | 222 | /* |
exopiped | 0:8ee38453bad9 | 223 | ** note_set_bufno |
exopiped | 0:8ee38453bad9 | 224 | * Set the index of the dma buffer to fill. |
exopiped | 0:8ee38453bad9 | 225 | * |
exopiped | 0:8ee38453bad9 | 226 | */ |
exopiped | 0:8ee38453bad9 | 227 | void note_set_bufno(int bufno) |
exopiped | 0:8ee38453bad9 | 228 | { |
exopiped | 0:8ee38453bad9 | 229 | note_bufno = bufno; |
exopiped | 0:8ee38453bad9 | 230 | } |
exopiped | 0:8ee38453bad9 | 231 | |
exopiped | 0:8ee38453bad9 | 232 | void note_attack(void) |
exopiped | 0:8ee38453bad9 | 233 | { |
exopiped | 0:8ee38453bad9 | 234 | note_state = NOTE_ATTACK; |
exopiped | 0:8ee38453bad9 | 235 | note_attack_bufcount = 0; |
exopiped | 0:8ee38453bad9 | 236 | note_attack_delta = ENVLP_MAX / note_attack_bufs; |
exopiped | 0:8ee38453bad9 | 237 | note_first_bufval=note_attack_bufcount*note_attack_delta; |
exopiped | 0:8ee38453bad9 | 238 | note_last_bufval=note_first_bufval + note_attack_delta; |
exopiped | 0:8ee38453bad9 | 239 | } |
exopiped | 0:8ee38453bad9 | 240 | |
exopiped | 0:8ee38453bad9 | 241 | bool note_attack_done(void) |
exopiped | 0:8ee38453bad9 | 242 | { |
exopiped | 0:8ee38453bad9 | 243 | if (note_attack_bufcount >= note_attack_bufs) { |
exopiped | 0:8ee38453bad9 | 244 | note_decay_bufcount = 0; |
exopiped | 0:8ee38453bad9 | 245 | note_decay_delta = (ENVLP_MAX >> 1) / note_decay_bufs; |
exopiped | 0:8ee38453bad9 | 246 | note_first_bufval = note_last_bufval; |
exopiped | 0:8ee38453bad9 | 247 | return true; |
exopiped | 0:8ee38453bad9 | 248 | } else { |
exopiped | 0:8ee38453bad9 | 249 | note_first_bufval=note_attack_bufcount*note_attack_delta; |
exopiped | 0:8ee38453bad9 | 250 | note_last_bufval=note_first_bufval+note_attack_delta; |
exopiped | 0:8ee38453bad9 | 251 | } |
exopiped | 0:8ee38453bad9 | 252 | return false; |
exopiped | 0:8ee38453bad9 | 253 | } |
exopiped | 0:8ee38453bad9 | 254 | |
exopiped | 0:8ee38453bad9 | 255 | bool note_decay_done(void) |
exopiped | 0:8ee38453bad9 | 256 | { |
exopiped | 0:8ee38453bad9 | 257 | if (note_decay_bufcount >= note_decay_bufs) { |
exopiped | 0:8ee38453bad9 | 258 | note_first_bufval = note_last_bufval; |
exopiped | 0:8ee38453bad9 | 259 | return true; |
exopiped | 0:8ee38453bad9 | 260 | } else { |
exopiped | 0:8ee38453bad9 | 261 | note_last_bufval=note_first_bufval - note_decay_delta; |
exopiped | 0:8ee38453bad9 | 262 | if (note_last_bufval < 0) { |
exopiped | 0:8ee38453bad9 | 263 | note_last_bufval=0; |
exopiped | 0:8ee38453bad9 | 264 | } |
exopiped | 0:8ee38453bad9 | 265 | } |
exopiped | 0:8ee38453bad9 | 266 | return false; |
exopiped | 0:8ee38453bad9 | 267 | } |
exopiped | 0:8ee38453bad9 | 268 | |
exopiped | 0:8ee38453bad9 | 269 | bool note_release_done(void) |
exopiped | 0:8ee38453bad9 | 270 | { |
exopiped | 0:8ee38453bad9 | 271 | if (note_first_bufval < 25) return true; |
exopiped | 0:8ee38453bad9 | 272 | return false; |
exopiped | 0:8ee38453bad9 | 273 | } |
exopiped | 0:8ee38453bad9 | 274 |