diff options
| author | Jack Humbert <jack.humb@gmail.com> | 2015-08-29 11:54:38 -0400 |
|---|---|---|
| committer | Jack Humbert <jack.humb@gmail.com> | 2015-08-29 11:54:38 -0400 |
| commit | 91176d854b8c9e49e88d494ba02c8e9c54fec914 (patch) | |
| tree | e21a68fbcd4e1d2c9d1b0d0d74d8ab47140d4847 /keyboard/planck/beeps.c | |
| parent | d63c2e3995ae464c4266a7bd348ffb2f43cf7377 (diff) | |
| download | qmk_firmware-91176d854b8c9e49e88d494ba02c8e9c54fec914.tar.gz qmk_firmware-91176d854b8c9e49e88d494ba02c8e9c54fec914.zip | |
speaker working, midi out
Diffstat (limited to 'keyboard/planck/beeps.c')
| -rw-r--r-- | keyboard/planck/beeps.c | 204 |
1 files changed, 93 insertions, 111 deletions
diff --git a/keyboard/planck/beeps.c b/keyboard/planck/beeps.c index 13e46e1da..335bfa7d4 100644 --- a/keyboard/planck/beeps.c +++ b/keyboard/planck/beeps.c | |||
| @@ -7,36 +7,19 @@ | |||
| 7 | #define PI 3.14159265 | 7 | #define PI 3.14159265 |
| 8 | #define CHANNEL OCR1C | 8 | #define CHANNEL OCR1C |
| 9 | 9 | ||
| 10 | volatile uint16_t sample; | ||
| 11 | uint16_t lastSample; | ||
| 12 | |||
| 13 | const int sounddata_length=200; | ||
| 14 | |||
| 15 | const unsigned char sounddata_data[] PROGMEM = {128, | ||
| 16 | 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | ||
| 17 | 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | ||
| 18 | 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | ||
| 19 | 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | ||
| 20 | 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | ||
| 21 | 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | ||
| 22 | 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | ||
| 23 | 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | ||
| 24 | 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | ||
| 25 | 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 129, 127, 129, 128, 127, 133, | ||
| 26 | 117, 109, 125, 121, 116, 132, 140, 126, 114, 114, 116, 120, 114, 93, 73, 66, 76, 116, 142, 129, | ||
| 27 | 128, 129, 120, 119, 118, 104, 87, 123, 181, 194, 196, 198, 189, 176, 160, 162, 172, 164, 164, 183, | ||
| 28 | 197, 188, 168, 167, 170, 165, 185, 209, 206, 196, 196, 199, 185, 162, 156, 167, 176, 173, 170, 166, | ||
| 29 | 151, 142, 140, 134, 130, 127, 113, 86, 67, 66, 69, 75, 73, 75, 86, 90, 91, 84, 65, 48, | ||
| 30 | 41, 30, 26, 56, 91, 88, 72, 70, 73, 82, 89, 73, 57, 60, 74, 89, 92, 77, 63, 60, | ||
| 31 | 53, 47, 56, 64, 63, 61, 56, 54, 52, 36, 16, 22, 51, 66, 67, 70, 76, 88, 99, 92, | ||
| 32 | 77, 74, 85, 100, 106, 97, 83, 85, 96, 108, 133, 160, 164}; | ||
| 33 | |||
| 34 | void delay_us(int count) { | 10 | void delay_us(int count) { |
| 35 | while(count--) { | 11 | while(count--) { |
| 36 | _delay_us(1); | 12 | _delay_us(1); |
| 37 | } | 13 | } |
| 38 | } | 14 | } |
| 39 | 15 | ||
| 16 | int voices = 0; | ||
| 17 | double frequency = 0; | ||
| 18 | int volume = 0; | ||
| 19 | |||
| 20 | double frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 21 | int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 22 | |||
| 40 | void beeps() { | 23 | void beeps() { |
| 41 | // DDRB |= (1<<7); | 24 | // DDRB |= (1<<7); |
| 42 | // PORTB &= ~(1<<7); | 25 | // PORTB &= ~(1<<7); |
| @@ -120,119 +103,118 @@ play_notes(); | |||
| 120 | 103 | ||
| 121 | } | 104 | } |
| 122 | 105 | ||
| 123 | void play_note(float freq, int length) { | 106 | void send_freq(double freq, int vol) { |
| 124 | DDRB |= (1<<7); | 107 | int duty = (((double)F_CPU) / freq); |
| 125 | PORTB &= ~(1<<7); | 108 | ICR3 = duty; // Set max to the period |
| 109 | OCR3A = duty >> (0x10 - vol); // Set compare to half the period | ||
| 110 | } | ||
| 126 | 111 | ||
| 127 | if (freq > 0) { | 112 | void stop_all_notes() { |
| 128 | int frequency = 1000000/freq; | 113 | voices = 0; |
| 129 | ICR1 = frequency; // Set max to the period | 114 | TCCR3A = 0; |
| 130 | OCR1C = frequency >> 1; // Set compare to half the period | 115 | TCCR3B = 0; |
| 116 | frequency = 0; | ||
| 131 | 117 | ||
| 132 | TCCR1A = _BV(COM1C1) | _BV(WGM11); // = 0b00001010; | 118 | for (int i = 0; i < 8; i++) { |
| 133 | TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; | 119 | frequencies[i] = 0; |
| 120 | volumes[i] = 0; | ||
| 134 | } | 121 | } |
| 135 | |||
| 136 | for (int i = 0; i < length; i++) { | ||
| 137 | _delay_us(50000); | ||
| 138 | } | ||
| 139 | |||
| 140 | TCCR1A &= ~(_BV(COM1C1)); | ||
| 141 | } | 122 | } |
| 142 | 123 | ||
| 143 | // This is called at 8000 Hz to load the next sample. | 124 | void stop_note(double freq) { |
| 144 | ISR(TIMER1_COMPA_vect) { | 125 | for (int i = 7; i >= 0; i--) { |
| 145 | if (sample >= sounddata_length) { | 126 | if (frequencies[i] == freq) { |
| 146 | if (sample == sounddata_length + lastSample) { | 127 | frequencies[i] = 0; |
| 147 | TIMSK1 &= ~_BV(OCIE1A); | 128 | volumes[i] = 0; |
| 148 | 129 | for (int j = i; (j < 7); j++) { | |
| 149 | // Disable the per-sample timer completely. | 130 | frequencies[j] = frequencies[j+1]; |
| 150 | TCCR1B &= ~_BV(CS10); | 131 | frequencies[j+1] = 0; |
| 151 | } | 132 | volumes[j] = volumes[j+1]; |
| 152 | else { | 133 | volumes[j+1] = 0; |
| 153 | OCR1C = sounddata_length + lastSample - sample; | 134 | } |
| 154 | } | 135 | } |
| 155 | } | 136 | } |
| 156 | else { | 137 | voices--; |
| 157 | OCR1C = pgm_read_byte(&sounddata_data[sample]); | 138 | if (voices == 0) { |
| 139 | TCCR3A = 0; | ||
| 140 | TCCR3B = 0; | ||
| 141 | frequency = 0; | ||
| 142 | } else { | ||
| 143 | double freq = frequencies[voices - 1]; | ||
| 144 | int vol = volumes[voices - 1]; | ||
| 145 | if (frequency < freq) { | ||
| 146 | for (double f = frequency; f <= freq; f += ((freq - frequency) / 500.0)) { | ||
| 147 | send_freq(f, vol); | ||
| 148 | } | ||
| 149 | } else if (frequency > freq) { | ||
| 150 | for (double f = frequency; f >= freq; f -= ((frequency - freq) / 500.0)) { | ||
| 151 | send_freq(f, vol); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | send_freq(freq, vol); | ||
| 155 | frequency = freq; | ||
| 156 | volume = vol; | ||
| 158 | } | 157 | } |
| 159 | |||
| 160 | ++sample; | ||
| 161 | } | 158 | } |
| 162 | 159 | ||
| 163 | void play_notes() { | 160 | void play_note(double freq, int vol) { |
| 164 | |||
| 165 | |||
| 166 | // Set up Timer 2 to do pulse width modulation on the speaker | ||
| 167 | // pin. | ||
| 168 | |||
| 169 | DDRB |= (1<<7); | ||
| 170 | PORTB &= ~(1<<7); | ||
| 171 | 161 | ||
| 172 | // Use internal clock (datasheet p.160) | 162 | if (freq > 0) { |
| 173 | // ASSR &= ~(_BV(EXCLK) | _BV(AS2)); | 163 | DDRC |= (1<<6); |
| 174 | 164 | ||
| 175 | // Set fast PWM mode (p.157) | 165 | TCCR3A = (1 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); |
| 176 | TCCR1A |= _BV(WGM21) | _BV(WGM20); | 166 | TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); |
| 177 | TCCR1B &= ~_BV(WGM22); | 167 | |
| 178 | 168 | if (frequency != 0) { | |
| 179 | // Do non-inverting PWM on pin OC2A (p.155) | 169 | if (frequency < freq) { |
| 180 | // On the Arduino this is pin 11. | 170 | for (double f = frequency; f <= freq; f += ((freq - frequency) / 500.0)) { |
| 181 | TCCR1A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0); | 171 | send_freq(f, vol); |
| 182 | TCCR1A &= ~(_BV(COM2B1) | _BV(COM2B0)); | 172 | } |
| 183 | // No prescaler (p.158) | 173 | } else if (frequency > freq) { |
| 184 | TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10); | 174 | for (double f = frequency; f >= freq; f -= ((frequency - freq) / 500.0)) { |
| 185 | 175 | send_freq(f, vol); | |
| 186 | // Set initial pulse width to the first sample. | 176 | } |
| 187 | OCR1A = pgm_read_byte(&sounddata_data[0]); | 177 | } |
| 188 | 178 | } | |
| 189 | 179 | send_freq(freq, vol); | |
| 190 | 180 | frequency = freq; | |
| 191 | 181 | volume = vol; | |
| 192 | cli(); | ||
| 193 | |||
| 194 | // Set CTC mode (Clear Timer on Compare Match) (p.133) | ||
| 195 | // Have to set OCR1A *after*, otherwise it gets reset to 0! | ||
| 196 | TCCR2B = (TCCR2B & ~_BV(WGM13)) | _BV(WGM12); | ||
| 197 | TCCR2A = TCCR2A & ~(_BV(WGM11) | _BV(WGM10)); | ||
| 198 | |||
| 199 | // No prescaler (p.134) | ||
| 200 | TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10); | ||
| 201 | |||
| 202 | // Set the compare register (OCR1A). | ||
| 203 | // OCR1A is a 16-bit register, so we have to do this with | ||
| 204 | // interrupts disabled to be safe. | ||
| 205 | // OCR2A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000 | ||
| 206 | OCR2A = 2000; | ||
| 207 | |||
| 208 | // Enable interrupt when TCNT1 == OCR1A (p.136) | ||
| 209 | TIMSK1 |= _BV(OCIE2A); | ||
| 210 | 182 | ||
| 211 | sample = 0; | 183 | frequencies[voices] = frequency; |
| 212 | sei(); | 184 | volumes[voices] = volume; |
| 185 | voices++; | ||
| 186 | } | ||
| 187 | // ICR3 = 0xFFFF; | ||
| 188 | // for (int i = 0; i < 10000; i++) { | ||
| 189 | // OCR3A = round((sin(i*freq)*.5)+.5)*0xFFFF; | ||
| 190 | // // _delay_us(50); | ||
| 191 | // } | ||
| 192 | |||
| 193 | // TCCR3A = 0; | ||
| 194 | // TCCR3B = 0; | ||
| 213 | } | 195 | } |
| 214 | 196 | ||
| 215 | void note(int x, float length) { | 197 | void note(int x, float length) { |
| 216 | DDRB |= (1<<1); | 198 | DDRC |= (1<<6); |
| 217 | int t = (int)(440*pow(2,-x/12.0)); // starting note | 199 | int t = (int)(440*pow(2,-x/12.0)); // starting note |
| 218 | for (int y = 0; y < length*1000/t; y++) { // note length | 200 | for (int y = 0; y < length*1000/t; y++) { // note length |
| 219 | PORTB |= (1<<1); | 201 | PORTC |= (1<<6); |
| 220 | delay_us(t); | 202 | delay_us(t); |
| 221 | PORTB &= ~(1<<1); | 203 | PORTC &= ~(1<<6); |
| 222 | delay_us(t); | 204 | delay_us(t); |
| 223 | } | 205 | } |
| 224 | PORTB &= ~(1<<1); | 206 | PORTC &= ~(1<<6); |
| 225 | } | 207 | } |
| 226 | 208 | ||
| 227 | void true_note(float x, float y, float length) { | 209 | void true_note(float x, float y, float length) { |
| 228 | for (uint32_t i = 0; i < length * 50; i++) { | 210 | for (uint32_t i = 0; i < length * 50; i++) { |
| 229 | uint32_t v = (uint32_t) (round(sin(PI*2*i*640000*pow(2, x/12.0))*.5+1 + sin(PI*2*i*640000*pow(2, y/12.0))*.5+1) / 2 * pow(2, 8)); | 211 | uint32_t v = (uint32_t) (round(sin(PI*2*i*640000*pow(2, x/12.0))*.5+1 + sin(PI*2*i*640000*pow(2, y/12.0))*.5+1) / 2 * pow(2, 8)); |
| 230 | for (int u = 0; u < 8; u++) { | 212 | for (int u = 0; u < 8; u++) { |
| 231 | if (v & (1 << u) && !(PORTB&(1<<1))) | 213 | if (v & (1 << u) && !(PORTC&(1<<6))) |
| 232 | PORTB |= (1<<1); | 214 | PORTC |= (1<<6); |
| 233 | else if (PORTB&(1<<1)) | 215 | else if (PORTC&(1<<6)) |
| 234 | PORTB &= ~(1<<1); | 216 | PORTC &= ~(1<<6); |
| 235 | } | 217 | } |
| 236 | } | 218 | } |
| 237 | PORTB &= ~(1<<1); | 219 | PORTC &= ~(1<<6); |
| 238 | } \ No newline at end of file | 220 | } \ No newline at end of file |
