85220e16307115bb4db4052e849feab99ced0dd6
[jackhill/qmk/firmware.git] / quantum / audio / audio.c
1 /* Copyright 2016 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <stdio.h>
18 #include <string.h>
19 //#include <math.h>
20 #if defined(__AVR__)
21 #include <avr/pgmspace.h>
22 #include <avr/interrupt.h>
23 #include <avr/io.h>
24 #endif
25 #include "print.h"
26 #include "audio.h"
27 #include "keymap.h"
28 #include "wait.h"
29
30 #include "eeconfig.h"
31
32 #define CPU_PRESCALER 8
33
34 // -----------------------------------------------------------------------------
35 // Timer Abstractions
36 // -----------------------------------------------------------------------------
37
38 // TIMSK3 - Timer/Counter #3 Interrupt Mask Register
39 // Turn on/off 3A interputs, stopping/enabling the ISR calls
40 #ifdef C6_AUDIO
41 #define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A)
42 #define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A)
43 #endif
44
45 #ifdef B5_AUDIO
46 #define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1A)
47 #define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1A)
48 #endif
49
50 // TCCR3A: Timer/Counter #3 Control Register
51 // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
52
53 #ifdef C6_AUDIO
54 #define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1);
55 #define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0));
56 #endif
57
58 #ifdef B5_AUDIO
59 #define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1A1);
60 #define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1A1) | _BV(COM1A0));
61 #endif
62
63 // Fast PWM Mode Controls
64
65 #ifdef C6_AUDIO
66 #define TIMER_3_PERIOD ICR3
67 #define TIMER_3_DUTY_CYCLE OCR3A
68 #endif
69
70 #ifdef B5_AUDIO
71 #define TIMER_1_PERIOD ICR1
72 #define TIMER_1_DUTY_CYCLE OCR1A
73 #endif
74
75
76 // -----------------------------------------------------------------------------
77
78
79 int voices = 0;
80 int voice_place = 0;
81 float frequency = 0;
82 float frequency_alt = 0;
83 int volume = 0;
84 long position = 0;
85
86 float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
87 int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
88 bool sliding = false;
89
90 float place = 0;
91
92 uint8_t * sample;
93 uint16_t sample_length = 0;
94
95 bool playing_notes = false;
96 bool playing_note = false;
97 float note_frequency = 0;
98 float note_length = 0;
99 uint8_t note_tempo = TEMPO_DEFAULT;
100 float note_timbre = TIMBRE_DEFAULT;
101 uint16_t note_position = 0;
102 float (* notes_pointer)[][2];
103 uint16_t notes_count;
104 bool notes_repeat;
105 bool note_resting = false;
106
107 uint8_t current_note = 0;
108 uint8_t rest_counter = 0;
109
110 #ifdef VIBRATO_ENABLE
111 float vibrato_counter = 0;
112 float vibrato_strength = .5;
113 float vibrato_rate = 0.125;
114 #endif
115
116 float polyphony_rate = 0;
117
118 static bool audio_initialized = false;
119
120 audio_config_t audio_config;
121
122 uint16_t envelope_index = 0;
123 bool glissando = true;
124
125 #ifndef STARTUP_SONG
126 #define STARTUP_SONG SONG(STARTUP_SOUND)
127 #endif
128 #ifndef AUDIO_ON_SONG
129 #define AUDIO_ON_SONG SONG(AUDIO_ON_SOUND)
130 #endif
131 #ifndef AUDIO_OFF_SONG
132 #define AUDIO_OFF_SONG SONG(AUDIO_OFF_SOUND)
133 #endif
134 float startup_song[][2] = STARTUP_SONG;
135 float audio_on_song[][2] = AUDIO_ON_SONG;
136 float audio_off_song[][2] = AUDIO_OFF_SONG;
137
138 void audio_init()
139 {
140
141 // Check EEPROM
142 if (!eeconfig_is_enabled())
143 {
144 eeconfig_init();
145 }
146 audio_config.raw = eeconfig_read_audio();
147
148 if (!audio_initialized) {
149
150 // Set port PC6 (OC3A and /OC4A) as output
151
152 #ifdef C6_AUDIO
153 DDRC |= _BV(PORTC6);
154 //#else
155 // DDRC |= _BV(PORTC6); // Why is PC6 being set as output low, if C6_audio isn't defined?
156 // PORTC &= ~_BV(PORTC6);
157 #endif
158
159 #ifdef B5_AUDIO
160 DDRB |= _BV(PORTB5);
161 //#else
162 // DDRB |= _BV(PORTB5); // Same as with PC6
163 // PORTB &= ~_BV(PORTB5);
164 #endif
165
166 #ifdef C6_AUDIO
167 DISABLE_AUDIO_COUNTER_3_ISR;
168 #endif
169
170 #ifdef B5_AUDIO
171 DISABLE_AUDIO_COUNTER_1_ISR;
172 #endif
173
174 // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
175 // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
176 // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A)
177 // Clock Select (CS3n) = 0b010 = Clock / 8
178
179 #ifdef C6_AUDIO
180 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
181 TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
182 #endif
183
184 #ifdef B5_AUDIO
185 TCCR1A = (0 << COM1A1) | (0 << COM1A0) | (1 << WGM11) | (0 << WGM10);
186 TCCR1B = (1 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10);
187
188 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (440 * CPU_PRESCALER));
189 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (440 * CPU_PRESCALER)) * note_timbre);
190 #endif
191
192 audio_initialized = true;
193 }
194
195 if (audio_config.enable) {
196 PLAY_SONG(startup_song);
197 }
198
199 }
200
201 void stop_all_notes()
202 {
203 dprintf("audio stop all notes");
204
205 if (!audio_initialized) {
206 audio_init();
207 }
208 voices = 0;
209
210
211 #ifdef C6_AUDIO
212 DISABLE_AUDIO_COUNTER_3_ISR;
213 DISABLE_AUDIO_COUNTER_3_OUTPUT;
214 #endif
215
216 #ifdef B5_AUDIO
217 DISABLE_AUDIO_COUNTER_1_ISR;
218 DISABLE_AUDIO_COUNTER_1_OUTPUT;
219 #endif
220
221 playing_notes = false;
222 playing_note = false;
223 frequency = 0;
224 frequency_alt = 0;
225 volume = 0;
226
227 for (uint8_t i = 0; i < 8; i++)
228 {
229 frequencies[i] = 0;
230 volumes[i] = 0;
231 }
232 }
233
234 void stop_note(float freq)
235 {
236 dprintf("audio stop note freq=%d", (int)freq);
237
238 if (playing_note) {
239 if (!audio_initialized) {
240 audio_init();
241 }
242 for (int i = 7; i >= 0; i--) {
243 if (frequencies[i] == freq) {
244 frequencies[i] = 0;
245 volumes[i] = 0;
246 for (int j = i; (j < 7); j++) {
247 frequencies[j] = frequencies[j+1];
248 frequencies[j+1] = 0;
249 volumes[j] = volumes[j+1];
250 volumes[j+1] = 0;
251 }
252 break;
253 }
254 }
255 voices--;
256 if (voices < 0)
257 voices = 0;
258 if (voice_place >= voices) {
259 voice_place = 0;
260 }
261 if (voices == 0) {
262 #ifdef C6_AUDIO
263 DISABLE_AUDIO_COUNTER_3_ISR;
264 DISABLE_AUDIO_COUNTER_3_OUTPUT;
265 #endif
266 #ifdef B5_AUDIO
267 DISABLE_AUDIO_COUNTER_1_ISR;
268 DISABLE_AUDIO_COUNTER_1_OUTPUT;
269 #endif
270 frequency = 0;
271 frequency_alt = 0;
272 volume = 0;
273 playing_note = false;
274 }
275 }
276 }
277
278 #ifdef VIBRATO_ENABLE
279
280 float mod(float a, int b)
281 {
282 float r = fmod(a, b);
283 return r < 0 ? r + b : r;
284 }
285
286 float vibrato(float average_freq) {
287 #ifdef VIBRATO_STRENGTH_ENABLE
288 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
289 #else
290 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
291 #endif
292 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0/average_freq)), VIBRATO_LUT_LENGTH);
293 return vibrated_freq;
294 }
295
296 #endif
297
298 #ifdef C6_AUDIO
299 ISR(TIMER3_COMPA_vect)
300 {
301 float freq;
302
303 if (playing_note) {
304 if (voices > 0) {
305
306 #ifdef B5_AUDIO
307 float freq_alt = 0;
308 if (voices > 1) {
309 if (polyphony_rate == 0) {
310 if (glissando) {
311 if (frequency_alt != 0 && frequency_alt < frequencies[voices - 2] && frequency_alt < frequencies[voices - 2] * pow(2, -440/frequencies[voices - 2]/12/2)) {
312 frequency_alt = frequency_alt * pow(2, 440/frequency_alt/12/2);
313 } else if (frequency_alt != 0 && frequency_alt > frequencies[voices - 2] && frequency_alt > frequencies[voices - 2] * pow(2, 440/frequencies[voices - 2]/12/2)) {
314 frequency_alt = frequency_alt * pow(2, -440/frequency_alt/12/2);
315 } else {
316 frequency_alt = frequencies[voices - 2];
317 }
318 } else {
319 frequency_alt = frequencies[voices - 2];
320 }
321
322 #ifdef VIBRATO_ENABLE
323 if (vibrato_strength > 0) {
324 freq_alt = vibrato(frequency_alt);
325 } else {
326 freq_alt = frequency_alt;
327 }
328 #else
329 freq_alt = frequency_alt;
330 #endif
331 }
332
333 if (envelope_index < 65535) {
334 envelope_index++;
335 }
336
337 freq_alt = voice_envelope(freq_alt);
338
339 if (freq_alt < 30.517578125) {
340 freq_alt = 30.52;
341 }
342
343 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq_alt * CPU_PRESCALER));
344 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq_alt * CPU_PRESCALER)) * note_timbre);
345 }
346 #endif
347
348 if (polyphony_rate > 0) {
349 if (voices > 1) {
350 voice_place %= voices;
351 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
352 voice_place = (voice_place + 1) % voices;
353 place = 0.0;
354 }
355 }
356
357 #ifdef VIBRATO_ENABLE
358 if (vibrato_strength > 0) {
359 freq = vibrato(frequencies[voice_place]);
360 } else {
361 freq = frequencies[voice_place];
362 }
363 #else
364 freq = frequencies[voice_place];
365 #endif
366 } else {
367 if (glissando) {
368 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) {
369 frequency = frequency * pow(2, 440/frequency/12/2);
370 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) {
371 frequency = frequency * pow(2, -440/frequency/12/2);
372 } else {
373 frequency = frequencies[voices - 1];
374 }
375 } else {
376 frequency = frequencies[voices - 1];
377 }
378
379 #ifdef VIBRATO_ENABLE
380 if (vibrato_strength > 0) {
381 freq = vibrato(frequency);
382 } else {
383 freq = frequency;
384 }
385 #else
386 freq = frequency;
387 #endif
388 }
389
390 if (envelope_index < 65535) {
391 envelope_index++;
392 }
393
394 freq = voice_envelope(freq);
395
396 if (freq < 30.517578125) {
397 freq = 30.52;
398 }
399
400 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
401 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
402 }
403 }
404
405 if (playing_notes) {
406 if (note_frequency > 0) {
407 #ifdef VIBRATO_ENABLE
408 if (vibrato_strength > 0) {
409 freq = vibrato(note_frequency);
410 } else {
411 freq = note_frequency;
412 }
413 #else
414 freq = note_frequency;
415 #endif
416
417 if (envelope_index < 65535) {
418 envelope_index++;
419 }
420 freq = voice_envelope(freq);
421
422 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
423 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
424 } else {
425 TIMER_3_PERIOD = 0;
426 TIMER_3_DUTY_CYCLE = 0;
427 }
428
429 note_position++;
430 bool end_of_note = false;
431 if (TIMER_3_PERIOD > 0) {
432 if (!note_resting)
433 end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF - 1));
434 else
435 end_of_note = (note_position >= (note_length));
436 } else {
437 end_of_note = (note_position >= (note_length));
438 }
439
440 if (end_of_note) {
441 current_note++;
442 if (current_note >= notes_count) {
443 if (notes_repeat) {
444 current_note = 0;
445 } else {
446 DISABLE_AUDIO_COUNTER_3_ISR;
447 DISABLE_AUDIO_COUNTER_3_OUTPUT;
448 playing_notes = false;
449 return;
450 }
451 }
452 if (!note_resting) {
453 note_resting = true;
454 current_note--;
455 if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
456 note_frequency = 0;
457 note_length = 1;
458 } else {
459 note_frequency = (*notes_pointer)[current_note][0];
460 note_length = 1;
461 }
462 } else {
463 note_resting = false;
464 envelope_index = 0;
465 note_frequency = (*notes_pointer)[current_note][0];
466 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
467 }
468
469 note_position = 0;
470 }
471 }
472
473 if (!audio_config.enable) {
474 playing_notes = false;
475 playing_note = false;
476 }
477 }
478 #endif
479
480 #ifdef B5_AUDIO
481 ISR(TIMER1_COMPA_vect)
482 {
483 #if defined(B5_AUDIO) && !defined(C6_AUDIO)
484 float freq = 0;
485
486 if (playing_note) {
487 if (voices > 0) {
488 if (polyphony_rate > 0) {
489 if (voices > 1) {
490 voice_place %= voices;
491 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
492 voice_place = (voice_place + 1) % voices;
493 place = 0.0;
494 }
495 }
496
497 #ifdef VIBRATO_ENABLE
498 if (vibrato_strength > 0) {
499 freq = vibrato(frequencies[voice_place]);
500 } else {
501 freq = frequencies[voice_place];
502 }
503 #else
504 freq = frequencies[voice_place];
505 #endif
506 } else {
507 if (glissando) {
508 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) {
509 frequency = frequency * pow(2, 440/frequency/12/2);
510 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) {
511 frequency = frequency * pow(2, -440/frequency/12/2);
512 } else {
513 frequency = frequencies[voices - 1];
514 }
515 } else {
516 frequency = frequencies[voices - 1];
517 }
518
519 #ifdef VIBRATO_ENABLE
520 if (vibrato_strength > 0) {
521 freq = vibrato(frequency);
522 } else {
523 freq = frequency;
524 }
525 #else
526 freq = frequency;
527 #endif
528 }
529
530 if (envelope_index < 65535) {
531 envelope_index++;
532 }
533
534 freq = voice_envelope(freq);
535
536 if (freq < 30.517578125) {
537 freq = 30.52;
538 }
539
540 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
541 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
542 }
543 }
544
545 if (playing_notes) {
546 if (note_frequency > 0) {
547 #ifdef VIBRATO_ENABLE
548 if (vibrato_strength > 0) {
549 freq = vibrato(note_frequency);
550 } else {
551 freq = note_frequency;
552 }
553 #else
554 freq = note_frequency;
555 #endif
556
557 if (envelope_index < 65535) {
558 envelope_index++;
559 }
560 freq = voice_envelope(freq);
561
562 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
563 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
564 } else {
565 TIMER_1_PERIOD = 0;
566 TIMER_1_DUTY_CYCLE = 0;
567 }
568
569 note_position++;
570 bool end_of_note = false;
571 if (TIMER_1_PERIOD > 0) {
572 if (!note_resting)
573 end_of_note = (note_position >= (note_length / TIMER_1_PERIOD * 0xFFFF - 1));
574 else
575 end_of_note = (note_position >= (note_length));
576 } else {
577 end_of_note = (note_position >= (note_length));
578 }
579
580 if (end_of_note) {
581 current_note++;
582 if (current_note >= notes_count) {
583 if (notes_repeat) {
584 current_note = 0;
585 } else {
586 DISABLE_AUDIO_COUNTER_1_ISR;
587 DISABLE_AUDIO_COUNTER_1_OUTPUT;
588 playing_notes = false;
589 return;
590 }
591 }
592 if (!note_resting) {
593 note_resting = true;
594 current_note--;
595 if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) {
596 note_frequency = 0;
597 note_length = 1;
598 } else {
599 note_frequency = (*notes_pointer)[current_note][0];
600 note_length = 1;
601 }
602 } else {
603 note_resting = false;
604 envelope_index = 0;
605 note_frequency = (*notes_pointer)[current_note][0];
606 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
607 }
608
609 note_position = 0;
610 }
611 }
612
613 if (!audio_config.enable) {
614 playing_notes = false;
615 playing_note = false;
616 }
617 #endif
618 }
619 #endif
620
621 void play_note(float freq, int vol) {
622
623 dprintf("audio play note freq=%d vol=%d", (int)freq, vol);
624
625 if (!audio_initialized) {
626 audio_init();
627 }
628
629 if (audio_config.enable && voices < 8) {
630 #ifdef C6_AUDIO
631 DISABLE_AUDIO_COUNTER_3_ISR;
632 #endif
633 #ifdef B5_AUDIO
634 DISABLE_AUDIO_COUNTER_1_ISR;
635 #endif
636
637 // Cancel notes if notes are playing
638 if (playing_notes)
639 stop_all_notes();
640
641 playing_note = true;
642
643 envelope_index = 0;
644
645 if (freq > 0) {
646 frequencies[voices] = freq;
647 volumes[voices] = vol;
648 voices++;
649 }
650
651 #ifdef C6_AUDIO
652 ENABLE_AUDIO_COUNTER_3_ISR;
653 ENABLE_AUDIO_COUNTER_3_OUTPUT;
654 #endif
655 #ifdef B5_AUDIO
656 #ifdef C6_AUDIO
657 if (voices > 1) {
658 ENABLE_AUDIO_COUNTER_1_ISR;
659 ENABLE_AUDIO_COUNTER_1_OUTPUT;
660 }
661 #else
662 ENABLE_AUDIO_COUNTER_1_ISR;
663 ENABLE_AUDIO_COUNTER_1_OUTPUT;
664 #endif
665 #endif
666 }
667
668 }
669
670 void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat)
671 {
672
673 if (!audio_initialized) {
674 audio_init();
675 }
676
677 if (audio_config.enable) {
678
679 #ifdef C6_AUDIO
680 DISABLE_AUDIO_COUNTER_3_ISR;
681 #endif
682 #ifdef B5_AUDIO
683 DISABLE_AUDIO_COUNTER_1_ISR;
684 #endif
685
686 // Cancel note if a note is playing
687 if (playing_note)
688 stop_all_notes();
689
690 playing_notes = true;
691
692 notes_pointer = np;
693 notes_count = n_count;
694 notes_repeat = n_repeat;
695
696 place = 0;
697 current_note = 0;
698
699 note_frequency = (*notes_pointer)[current_note][0];
700 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
701 note_position = 0;
702
703
704 #ifdef C6_AUDIO
705 ENABLE_AUDIO_COUNTER_3_ISR;
706 ENABLE_AUDIO_COUNTER_3_OUTPUT;
707 #endif
708 #ifdef B5_AUDIO
709 #ifndef C6_AUDIO
710 ENABLE_AUDIO_COUNTER_1_ISR;
711 ENABLE_AUDIO_COUNTER_1_OUTPUT;
712 #endif
713 #endif
714 }
715
716 }
717
718 bool is_playing_notes(void) {
719 return playing_notes;
720 }
721
722 bool is_audio_on(void) {
723 return (audio_config.enable != 0);
724 }
725
726 void audio_toggle(void) {
727 audio_config.enable ^= 1;
728 eeconfig_update_audio(audio_config.raw);
729 if (audio_config.enable)
730 audio_on_user();
731 }
732
733 void audio_on(void) {
734 audio_config.enable = 1;
735 eeconfig_update_audio(audio_config.raw);
736 audio_on_user();
737 PLAY_SONG(audio_on_song);
738 }
739
740 void audio_off(void) {
741 PLAY_SONG(audio_off_song);
742 wait_ms(100);
743 stop_all_notes();
744 audio_config.enable = 0;
745 eeconfig_update_audio(audio_config.raw);
746 }
747
748 #ifdef VIBRATO_ENABLE
749
750 // Vibrato rate functions
751
752 void set_vibrato_rate(float rate) {
753 vibrato_rate = rate;
754 }
755
756 void increase_vibrato_rate(float change) {
757 vibrato_rate *= change;
758 }
759
760 void decrease_vibrato_rate(float change) {
761 vibrato_rate /= change;
762 }
763
764 #ifdef VIBRATO_STRENGTH_ENABLE
765
766 void set_vibrato_strength(float strength) {
767 vibrato_strength = strength;
768 }
769
770 void increase_vibrato_strength(float change) {
771 vibrato_strength *= change;
772 }
773
774 void decrease_vibrato_strength(float change) {
775 vibrato_strength /= change;
776 }
777
778 #endif /* VIBRATO_STRENGTH_ENABLE */
779
780 #endif /* VIBRATO_ENABLE */
781
782 // Polyphony functions
783
784 void set_polyphony_rate(float rate) {
785 polyphony_rate = rate;
786 }
787
788 void enable_polyphony() {
789 polyphony_rate = 5;
790 }
791
792 void disable_polyphony() {
793 polyphony_rate = 0;
794 }
795
796 void increase_polyphony_rate(float change) {
797 polyphony_rate *= change;
798 }
799
800 void decrease_polyphony_rate(float change) {
801 polyphony_rate /= change;
802 }
803
804 // Timbre function
805
806 void set_timbre(float timbre) {
807 note_timbre = timbre;
808 }
809
810 // Tempo functions
811
812 void set_tempo(uint8_t tempo) {
813 note_tempo = tempo;
814 }
815
816 void decrease_tempo(uint8_t tempo_change) {
817 note_tempo += tempo_change;
818 }
819
820 void increase_tempo(uint8_t tempo_change) {
821 if (note_tempo - tempo_change < 10) {
822 note_tempo = 10;
823 } else {
824 note_tempo -= tempo_change;
825 }
826 }