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