]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/audio.c
Fixup RGBLIGHT support for clueboard2
[qmk_firmware.git] / quantum / audio.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <math.h>
4 #include <avr/pgmspace.h>
5 #include <avr/interrupt.h>
6 #include <avr/io.h>
7
8 #include "audio.h"
9 #include "keymap_common.h"
10
11 #define PI 3.14159265
12
13 // #define PWM_AUDIO
14
15 #ifdef PWM_AUDIO
16     #include "wave.h"
17     #define SAMPLE_DIVIDER 39
18     #define SAMPLE_RATE (2000000.0/SAMPLE_DIVIDER/2048)
19     // Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap
20 #endif
21
22 void delay_us(int count) {
23   while(count--) {
24     _delay_us(1);
25   }
26 }
27
28 int voices = 0;
29 int voice_place = 0;
30 double frequency = 0;
31 int volume = 0;
32 long position = 0;
33
34 double frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
35 int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
36 bool sliding = false;
37
38 int max = 0xFF;
39 float sum = 0;
40 int value = 128;
41 float place = 0;
42 float places[8] = {0, 0, 0, 0, 0, 0, 0, 0};
43
44 uint16_t place_int = 0;
45 bool repeat = true;
46 uint8_t * sample;
47 uint16_t sample_length = 0;
48
49
50 bool notes = false;
51 bool note = false;
52 float note_frequency = 0;
53 float note_length = 0;
54 uint16_t note_position = 0;
55 float (* notes_pointer)[][2];
56 uint8_t notes_length;
57 bool notes_repeat;
58 uint8_t current_note = 0;
59
60 void stop_all_notes() {
61     voices = 0;
62     #ifdef PWM_AUDIO
63         TIMSK3 &= ~_BV(OCIE3A);
64     #else
65         TIMSK3 &= ~_BV(OCIE3A);
66         TCCR3A &= ~_BV(COM3A1);
67     #endif
68     notes = false;
69     note = false;
70     frequency = 0;
71     volume = 0;
72
73     for (int i = 0; i < 8; i++) {
74         frequencies[i] = 0;
75         volumes[i] = 0;
76     }
77 }
78
79 void stop_note(double freq) {
80     #ifdef PWM_AUDIO
81         freq = freq / SAMPLE_RATE;
82     #endif
83     for (int i = 7; i >= 0; i--) {
84         if (frequencies[i] == freq) {
85             frequencies[i] = 0;
86             volumes[i] = 0;
87             for (int j = i; (j < 7); j++) {
88                 frequencies[j] = frequencies[j+1];
89                 frequencies[j+1] = 0;
90                 volumes[j] = volumes[j+1];
91                 volumes[j+1] = 0;
92             }
93         }
94     }
95     voices--;
96     if (voices < 0)
97         voices = 0;
98     if (voices == 0) {
99         #ifdef PWM_AUDIO
100             TIMSK3 &= ~_BV(OCIE3A);
101         #else
102             TIMSK3 &= ~_BV(OCIE3A);
103             TCCR3A &= ~_BV(COM3A1);
104         #endif
105         frequency = 0;
106         volume = 0;
107         note = false;
108     } else {
109         double freq = frequencies[voices - 1];
110         int vol = volumes[voices - 1];
111         double starting_f = frequency;
112         if (frequency < freq) {
113             sliding = true;
114             for (double f = starting_f; f <= freq; f += ((freq - starting_f) / 2000.0)) {
115                 frequency = f;
116             }
117             sliding = false;
118         } else if (frequency > freq) {
119             sliding = true;
120             for (double f = starting_f; f >= freq; f -= ((starting_f - freq) / 2000.0)) {
121                 frequency = f;
122             }
123             sliding = false;
124         }
125         frequency = freq;
126         volume = vol;
127     }
128 }
129
130 void init_notes() {
131
132     #ifdef PWM_AUDIO
133         PLLFRQ = _BV(PDIV2);
134         PLLCSR = _BV(PLLE);
135         while(!(PLLCSR & _BV(PLOCK)));
136         PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */
137
138         /* Init a fast PWM on Timer4 */
139         TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */
140         TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */
141         OCR4A = 0;
142
143         /* Enable the OC4A output */
144         DDRC |= _BV(PORTC6);
145
146         TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs
147         
148         TCCR3A = 0x0; // Options not needed
149         TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC
150         OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback
151     #else
152         DDRC |= _BV(PORTC6);
153
154         TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs
155
156         TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
157         TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
158     #endif
159 }
160
161
162 ISR(TIMER3_COMPA_vect) {
163
164     if (note) {
165         #ifdef PWM_AUDIO
166             if (voices == 1) {
167                 // SINE
168                 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2;
169             
170                 // SQUARE
171                 // if (((int)place) >= 1024){
172                 //     OCR4A = 0xFF >> 2;
173                 // } else {
174                 //     OCR4A = 0x00;
175                 // }
176                 
177                 // SAWTOOTH
178                 // OCR4A = (int)place / 4;
179
180                 // TRIANGLE
181                 // if (((int)place) >= 1024) {
182                 //     OCR4A = (int)place / 2;
183                 // } else {
184                 //     OCR4A = 2048 - (int)place / 2;
185                 // }
186
187                 place += frequency;
188
189                 if (place >= SINE_LENGTH)
190                     place -= SINE_LENGTH;
191
192             } else {
193                 int sum = 0;
194                 for (int i = 0; i < voices; i++) {
195                     // SINE
196                     sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2;
197
198                     // SQUARE
199                     // if (((int)places[i]) >= 1024){
200                     //     sum += 0xFF >> 2;
201                     // } else {
202                     //     sum += 0x00;
203                     // }
204
205                     places[i] += frequencies[i];
206
207                     if (places[i] >= SINE_LENGTH)
208                         places[i] -= SINE_LENGTH;
209                 }
210                 OCR4A = sum;
211             }
212         #else
213             if (frequency > 0) {
214                 // ICR3 = (int)(((double)F_CPU) / frequency); // Set max to the period
215                 // OCR3A = (int)(((double)F_CPU) / frequency) >> 1; // Set compare to half the period
216                 if (place > 10) {
217                     voice_place = (voice_place + 1) % voices;
218                     place = 0.0;
219                 }
220                 ICR3 = (int)(((double)F_CPU) / frequencies[voice_place]); // Set max to the period
221                 OCR3A = (int)(((double)F_CPU) / frequencies[voice_place]) >> 1; // Set compare to half the period
222                 place++;
223             }
224         #endif
225     }
226
227     // SAMPLE
228     // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]);
229
230     // place_int++;
231
232     // if (place_int >= sample_length)
233     //     if (repeat)
234     //         place_int -= sample_length;
235     //     else
236     //         TIMSK3 &= ~_BV(OCIE3A);
237
238
239     if (notes) {
240         #ifdef PWM_AUDIO
241             OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0;
242
243             place += note_frequency;
244             if (place >= SINE_LENGTH)
245                 place -= SINE_LENGTH;
246         #else
247             if (note_frequency > 0) {
248                 ICR3 = (int)(((double)F_CPU) / note_frequency); // Set max to the period
249                 OCR3A = (int)(((double)F_CPU) / note_frequency) >> 1; // Set compare to half the period
250             }
251         #endif
252
253
254         note_position++;
255         if (note_position >= note_length) {
256             current_note++;
257             if (current_note >= notes_length) {
258                 if (notes_repeat) {
259                     current_note = 0;
260                 } else {
261                     #ifdef PWM_AUDIO
262                         TIMSK3 &= ~_BV(OCIE3A);
263                     #else
264                         TIMSK3 &= ~_BV(OCIE3A);
265                         TCCR3A &= ~_BV(COM3A1);
266                     #endif
267                     notes = false;
268                     return;
269                 }
270             }
271             #ifdef PWM_AUDIO
272                 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
273                 note_length = (*notes_pointer)[current_note][1];
274             #else
275                 note_frequency = (*notes_pointer)[current_note][0];
276                 note_length = (*notes_pointer)[current_note][1] / 4;
277             #endif
278             note_position = 0;
279         }
280
281     }
282
283 }
284
285 void play_notes(float (*np)[][2], uint8_t n_length, bool n_repeat) {
286     if (note)
287         stop_all_notes();
288     notes = true;
289
290     notes_pointer = np;
291     notes_length = n_length;
292     notes_repeat = n_repeat;
293
294     place = 0;
295     current_note = 0;
296     #ifdef PWM_AUDIO
297         note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
298         note_length = (*notes_pointer)[current_note][1];
299     #else
300         note_frequency = (*notes_pointer)[current_note][0];
301         note_length = (*notes_pointer)[current_note][1] / 4;
302     #endif
303     note_position = 0;
304
305
306     #ifdef PWM_AUDIO
307         TIMSK3 |= _BV(OCIE3A);
308     #else
309         TIMSK3 |= _BV(OCIE3A);
310         TCCR3A |= _BV(COM3A1);
311     #endif
312 }
313
314 void play_sample(uint8_t * s, uint16_t l, bool r) {
315     stop_all_notes();
316     place_int = 0;
317     sample = s;
318     sample_length = l;
319     repeat = r;
320
321     #ifdef PWM_AUDIO
322         TIMSK3 |= _BV(OCIE3A);
323     #else
324     #endif
325 }
326
327 void play_note(double freq, int vol) {
328     if (notes)
329         stop_all_notes();
330     note = true;
331     #ifdef PWM_AUDIO
332         freq = freq / SAMPLE_RATE;
333     #endif
334     if (freq > 0) {
335         if (frequency != 0) {
336             double starting_f = frequency;
337             if (frequency < freq) {
338                 for (double f = starting_f; f <= freq; f += ((freq - starting_f) / 2000.0)) {   
339                     frequency = f;
340                 }
341             } else if (frequency > freq) {
342                 for (double f = starting_f; f >= freq; f -= ((starting_f - freq) / 2000.0)) {
343                     frequency = f;
344                 }
345             }
346         }
347         frequency = freq;
348         volume = vol;
349
350         frequencies[voices] = frequency;
351         volumes[voices] = volume;
352         voices++;
353     }
354
355     #ifdef PWM_AUDIO
356         TIMSK3 |= _BV(OCIE3A);
357     #else
358         TIMSK3 |= _BV(OCIE3A);
359         TCCR3A |= _BV(COM3A1);
360     #endif
361
362 }