]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/audio.c
Merge remote-tracking branch 'refs/remotes/origin/personal_atomic_planck'
[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 #include "print.h"
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 float note_tempo = TEMPO_DEFAULT;
61 float note_timbre = TIMBRE_DEFAULT;
62 uint16_t note_position = 0;
63 float (* notes_pointer)[][2];
64 uint8_t notes_count;
65 bool notes_repeat;
66 float notes_rest;
67 bool note_resting = false;
68
69 uint8_t current_note = 0;
70 uint8_t rest_counter = 0;
71
72 audio_config_t audio_config;
73
74
75 void audio_toggle(void) {
76     audio_config.enable ^= 1;
77     eeconfig_write_audio(audio_config.raw);
78 }
79
80 void audio_on(void) {
81     audio_config.enable = 1;
82     eeconfig_write_audio(audio_config.raw);
83 }
84
85 void audio_off(void) {
86     audio_config.enable = 0;
87     eeconfig_write_audio(audio_config.raw);
88 }
89
90
91 void stop_all_notes() {
92     voices = 0;
93     #ifdef PWM_AUDIO
94         TIMSK3 &= ~_BV(OCIE3A);
95     #else
96         TIMSK3 &= ~_BV(OCIE3A);
97         TCCR3A &= ~_BV(COM3A1);
98     #endif
99     notes = false;
100     note = false;
101     frequency = 0;
102     volume = 0;
103
104     for (int i = 0; i < 8; i++) {
105         frequencies[i] = 0;
106         volumes[i] = 0;
107     }
108 }
109
110 void stop_note(double freq) {
111     if (note) {
112         #ifdef PWM_AUDIO
113             freq = freq / SAMPLE_RATE;
114         #endif
115         for (int i = 7; i >= 0; i--) {
116             if (frequencies[i] == freq) {
117                 frequencies[i] = 0;
118                 volumes[i] = 0;
119                 for (int j = i; (j < 7); j++) {
120                     frequencies[j] = frequencies[j+1];
121                     frequencies[j+1] = 0;
122                     volumes[j] = volumes[j+1];
123                     volumes[j+1] = 0;
124                 }
125             }
126         }
127         voices--;
128         if (voices < 0)
129             voices = 0;
130         if (voices == 0) {
131             #ifdef PWM_AUDIO
132                 TIMSK3 &= ~_BV(OCIE3A);
133             #else
134                 TIMSK3 &= ~_BV(OCIE3A);
135                 TCCR3A &= ~_BV(COM3A1);
136             #endif
137             frequency = 0;
138             volume = 0;
139             note = false;
140         } else {
141             double freq = frequencies[voices - 1];
142             int vol = volumes[voices - 1];
143             double starting_f = frequency;
144             if (frequency < freq) {
145                 sliding = true;
146                 for (double f = starting_f; f <= freq; f += ((freq - starting_f) / 2000.0)) {
147                     frequency = f;
148                 }
149                 sliding = false;
150             } else if (frequency > freq) {
151                 sliding = true;
152                 for (double f = starting_f; f >= freq; f -= ((starting_f - freq) / 2000.0)) {
153                     frequency = f;
154                 }
155                 sliding = false;
156             }
157             frequency = freq;
158             volume = vol;
159         }
160     }
161 }
162
163 void init_notes() {
164
165     /* check signature */
166     if (!eeconfig_is_enabled()) {
167         eeconfig_init();
168     }
169     audio_config.raw = eeconfig_read_audio();
170
171     #ifdef PWM_AUDIO
172         PLLFRQ = _BV(PDIV2);
173         PLLCSR = _BV(PLLE);
174         while(!(PLLCSR & _BV(PLOCK)));
175         PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */
176
177         /* Init a fast PWM on Timer4 */
178         TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */
179         TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */
180         OCR4A = 0;
181
182         /* Enable the OC4A output */
183         DDRC |= _BV(PORTC6);
184
185         TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs
186
187         TCCR3A = 0x0; // Options not needed
188         TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC
189         OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback
190     #else
191         DDRC |= _BV(PORTC6);
192
193         TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs
194
195         TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
196         TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
197     #endif
198 }
199
200
201 ISR(TIMER3_COMPA_vect) {
202     if (note) {
203         #ifdef PWM_AUDIO
204             if (voices == 1) {
205                 // SINE
206                 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2;
207
208                 // SQUARE
209                 // if (((int)place) >= 1024){
210                 //     OCR4A = 0xFF >> 2;
211                 // } else {
212                 //     OCR4A = 0x00;
213                 // }
214
215                 // SAWTOOTH
216                 // OCR4A = (int)place / 4;
217
218                 // TRIANGLE
219                 // if (((int)place) >= 1024) {
220                 //     OCR4A = (int)place / 2;
221                 // } else {
222                 //     OCR4A = 2048 - (int)place / 2;
223                 // }
224
225                 place += frequency;
226
227                 if (place >= SINE_LENGTH)
228                     place -= SINE_LENGTH;
229
230             } else {
231                 int sum = 0;
232                 for (int i = 0; i < voices; i++) {
233                     // SINE
234                     sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2;
235
236                     // SQUARE
237                     // if (((int)places[i]) >= 1024){
238                     //     sum += 0xFF >> 2;
239                     // } else {
240                     //     sum += 0x00;
241                     // }
242
243                     places[i] += frequencies[i];
244
245                     if (places[i] >= SINE_LENGTH)
246                         places[i] -= SINE_LENGTH;
247                 }
248                 OCR4A = sum;
249             }
250         #else
251             if (frequency > 0) {
252                 // ICR3 = (int)(((double)F_CPU) / frequency); // Set max to the period
253                 // OCR3A = (int)(((double)F_CPU) / frequency) >> 1; // Set compare to half the period
254                 voice_place %= voices;
255                 if (place > (frequencies[voice_place] / 50)) {
256                     voice_place = (voice_place + 1) % voices;
257                     place = 0.0;
258                 }
259                 ICR3 = (int)(((double)F_CPU) / (frequencies[voice_place] * CPU_PRESCALER)); // Set max to the period
260                 OCR3A = (int)((((double)F_CPU) / (frequencies[voice_place] * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
261                 //OCR3A = (int)(((double)F_CPU) / (frequencies[voice_place] * CPU_PRESCALER)) >> 1 * duty_place; // Set compare to half the period
262                 place++;
263                 // if (duty_counter > (frequencies[voice_place] / 500)) {
264                 //     duty_place = (duty_place % 3) + 1;
265                 //     duty_counter = 0;
266                 // }
267                 // duty_counter++;
268             }
269         #endif
270     }
271
272     // SAMPLE
273     // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]);
274
275     // place_int++;
276
277     // if (place_int >= sample_length)
278     //     if (repeat)
279     //         place_int -= sample_length;
280     //     else
281     //         TIMSK3 &= ~_BV(OCIE3A);
282
283
284     if (notes) {
285         #ifdef PWM_AUDIO
286             OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0;
287
288             place += note_frequency;
289             if (place >= SINE_LENGTH)
290                 place -= SINE_LENGTH;
291         #else
292             if (note_frequency > 0) {
293                 ICR3 = (int)(((double)F_CPU) / (note_frequency * CPU_PRESCALER)); // Set max to the period
294                 OCR3A = (int)((((double)F_CPU) / (note_frequency * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
295             } else {
296                 ICR3 = 0;
297                 OCR3A = 0;
298             }
299         #endif
300
301
302         note_position++;
303         bool end_of_note = false;
304         if (ICR3 > 0)
305             end_of_note = (note_position >= (note_length / ICR3 * 0xFFFF));
306         else
307             end_of_note = (note_position >= (note_length * 0x7FF));
308         if (end_of_note) {
309             current_note++;
310             if (current_note >= notes_count) {
311                 if (notes_repeat) {
312                     current_note = 0;
313                 } else {
314                     #ifdef PWM_AUDIO
315                         TIMSK3 &= ~_BV(OCIE3A);
316                     #else
317                         TIMSK3 &= ~_BV(OCIE3A);
318                         TCCR3A &= ~_BV(COM3A1);
319                     #endif
320                     notes = false;
321                     return;
322                 }
323             }
324             if (!note_resting && (notes_rest > 0)) {
325                 note_resting = true;
326                 note_frequency = 0;
327                 note_length = notes_rest;
328                 current_note--;
329             } else {
330                 note_resting = false;
331                 #ifdef PWM_AUDIO
332                     note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
333                     note_length = (*notes_pointer)[current_note][1] * (note_tempo / 100);
334                 #else
335                     note_frequency = (*notes_pointer)[current_note][0];
336                     note_length = ((*notes_pointer)[current_note][1] / 4) * (note_tempo / 100);
337                 #endif
338             }
339             note_position = 0;
340         }
341
342     }
343
344     if (!audio_config.enable) {
345         notes = false;
346         note = false;
347     }
348 }
349
350 void play_notes(float (*np)[][2], uint8_t n_count, bool n_repeat, float n_rest) {
351
352 if (audio_config.enable) {
353
354         // Cancel note if a note is playing
355     if (note)
356         stop_all_notes();
357     notes = true;
358
359     notes_pointer = np;
360     notes_count = n_count;
361     notes_repeat = n_repeat;
362     notes_rest = n_rest;
363
364     place = 0;
365     current_note = 0;
366     #ifdef PWM_AUDIO
367         note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
368         note_length = (*notes_pointer)[current_note][1] * (note_tempo / 100);
369     #else
370         note_frequency = (*notes_pointer)[current_note][0];
371         note_length = ((*notes_pointer)[current_note][1] / 4) * (note_tempo / 100);
372     #endif
373     note_position = 0;
374
375
376     #ifdef PWM_AUDIO
377         TIMSK3 |= _BV(OCIE3A);
378     #else
379         TIMSK3 |= _BV(OCIE3A);
380         TCCR3A |= _BV(COM3A1);
381     #endif
382
383 }
384
385 }
386
387 void play_sample(uint8_t * s, uint16_t l, bool r) {
388
389 if (audio_config.enable) {
390
391     stop_all_notes();
392     place_int = 0;
393     sample = s;
394     sample_length = l;
395     repeat = r;
396
397     #ifdef PWM_AUDIO
398         TIMSK3 |= _BV(OCIE3A);
399     #else
400     #endif
401
402 }
403
404 }
405
406 void play_note(double freq, int vol) {
407
408 if (audio_config.enable && voices < 8) {
409
410     // Cancel notes if notes are playing
411     if (notes)
412         stop_all_notes();
413     note = true;
414     #ifdef PWM_AUDIO
415         freq = freq / SAMPLE_RATE;
416     #endif
417     if (freq > 0) {
418         if (frequency != 0) {
419             double starting_f = frequency;
420             if (frequency < freq) {
421                 for (double f = starting_f; f <= freq; f += ((freq - starting_f) / 2000.0)) {
422                     frequency = f;
423                 }
424             } else if (frequency > freq) {
425                 for (double f = starting_f; f >= freq; f -= ((starting_f - freq) / 2000.0)) {
426                     frequency = f;
427                 }
428             }
429         }
430         frequency = freq;
431         volume = vol;
432
433         frequencies[voices] = frequency;
434         volumes[voices] = volume;
435         voices++;
436     }
437
438     #ifdef PWM_AUDIO
439         TIMSK3 |= _BV(OCIE3A);
440     #else
441         TIMSK3 |= _BV(OCIE3A);
442         TCCR3A |= _BV(COM3A1);
443     #endif
444
445 }
446
447 }
448
449 void set_timbre(float timbre)
450 {
451         note_timbre = timbre;
452 }
453
454 void set_tempo(float tempo)
455 {
456         note_tempo = tempo;
457 }
458
459 void decrease_tempo(uint8_t tempo_change)
460 {
461         note_tempo += (float) tempo_change;
462 }
463
464 void increase_tempo(uint8_t tempo_change)
465 {
466         if (note_tempo - (float) tempo_change < 10)
467                 {
468                         note_tempo = 10;
469                 }
470         else
471                 {
472                 note_tempo -= (float) tempo_change;
473                 }
474 }
475
476 //------------------------------------------------------------------------------
477 // Override these functions in your keymap file to play different tunes on
478 // startup and bootloader jump
479 __attribute__ ((weak))
480 void play_startup_tone()
481 {
482 }
483
484 __attribute__ ((weak))
485 void play_goodbye_tone()
486 {
487 }
488 //------------------------------------------------------------------------------