aboutsummaryrefslogtreecommitdiff
path: root/quantum/audio/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/audio/audio.c')
-rw-r--r--quantum/audio/audio.c607
1 files changed, 607 insertions, 0 deletions
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c
new file mode 100644
index 000000000..3225557ba
--- /dev/null
+++ b/quantum/audio/audio.c
@@ -0,0 +1,607 @@
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#ifdef VIBRATO_ENABLE
14 #include "vibrato_lut.h"
15#endif
16
17#define PI 3.14159265
18
19#define CPU_PRESCALER 8
20
21#ifdef PWM_AUDIO
22 #include "wave.h"
23 #define SAMPLE_DIVIDER 39
24 #define SAMPLE_RATE (2000000.0/SAMPLE_DIVIDER/2048)
25 // Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap
26
27 float places[8] = {0, 0, 0, 0, 0, 0, 0, 0};
28 uint16_t place_int = 0;
29 bool repeat = true;
30#endif
31
32void delay_us(int count) {
33 while(count--) {
34 _delay_us(1);
35 }
36}
37
38int voices = 0;
39int voice_place = 0;
40float frequency = 0;
41int volume = 0;
42long position = 0;
43
44float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
45int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
46bool sliding = false;
47
48int max = 0xFF;
49float sum = 0;
50float place = 0;
51
52uint8_t * sample;
53uint16_t sample_length = 0;
54// float freq = 0;
55
56bool notes = false;
57bool note = false;
58float note_frequency = 0;
59float note_length = 0;
60float note_tempo = TEMPO_DEFAULT;
61float note_timbre = TIMBRE_DEFAULT;
62uint16_t note_position = 0;
63float (* notes_pointer)[][2];
64uint16_t notes_count;
65bool notes_repeat;
66float notes_rest;
67bool note_resting = false;
68
69uint8_t current_note = 0;
70uint8_t rest_counter = 0;
71
72#ifdef VIBRATO_ENABLE
73float vibrato_counter = 0;
74float vibrato_strength = .5;
75float vibrato_rate = 0.125;
76#endif
77
78float polyphony_rate = 0;
79
80bool inited = false;
81
82audio_config_t audio_config;
83
84uint16_t envelope_index = 0;
85
86void audio_toggle(void) {
87 audio_config.enable ^= 1;
88 eeconfig_write_audio(audio_config.raw);
89}
90
91void audio_on(void) {
92 audio_config.enable = 1;
93 eeconfig_write_audio(audio_config.raw);
94}
95
96void audio_off(void) {
97 audio_config.enable = 0;
98 eeconfig_write_audio(audio_config.raw);
99}
100
101#ifdef VIBRATO_ENABLE
102// Vibrato rate functions
103
104void set_vibrato_rate(float rate) {
105 vibrato_rate = rate;
106}
107
108void increase_vibrato_rate(float change) {
109 vibrato_rate *= change;
110}
111
112void decrease_vibrato_rate(float change) {
113 vibrato_rate /= change;
114}
115
116#ifdef VIBRATO_STRENGTH_ENABLE
117
118void set_vibrato_strength(float strength) {
119 vibrato_strength = strength;
120}
121
122void increase_vibrato_strength(float change) {
123 vibrato_strength *= change;
124}
125
126void decrease_vibrato_strength(float change) {
127 vibrato_strength /= change;
128}
129
130#endif
131
132#endif
133
134// Polyphony functions
135
136void set_polyphony_rate(float rate) {
137 polyphony_rate = rate;
138}
139
140void enable_polyphony() {
141 polyphony_rate = 5;
142}
143
144void disable_polyphony() {
145 polyphony_rate = 0;
146}
147
148void increase_polyphony_rate(float change) {
149 polyphony_rate *= change;
150}
151
152void decrease_polyphony_rate(float change) {
153 polyphony_rate /= change;
154}
155
156// Timbre function
157
158void set_timbre(float timbre) {
159 note_timbre = timbre;
160}
161
162// Tempo functions
163
164void set_tempo(float tempo) {
165 note_tempo = tempo;
166}
167
168void decrease_tempo(uint8_t tempo_change) {
169 note_tempo += (float) tempo_change;
170}
171
172void increase_tempo(uint8_t tempo_change) {
173 if (note_tempo - (float) tempo_change < 10) {
174 note_tempo = 10;
175 } else {
176 note_tempo -= (float) tempo_change;
177 }
178}
179
180void audio_init() {
181
182 /* check signature */
183 if (!eeconfig_is_enabled()) {
184 eeconfig_init();
185 }
186 audio_config.raw = eeconfig_read_audio();
187
188 #ifdef PWM_AUDIO
189 PLLFRQ = _BV(PDIV2);
190 PLLCSR = _BV(PLLE);
191 while(!(PLLCSR & _BV(PLOCK)));
192 PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */
193
194 /* Init a fast PWM on Timer4 */
195 TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */
196 TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */
197 OCR4A = 0;
198
199 /* Enable the OC4A output */
200 DDRC |= _BV(PORTC6);
201
202 TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs
203
204 TCCR3A = 0x0; // Options not needed
205 TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC
206 OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback
207 #else
208 DDRC |= _BV(PORTC6);
209
210 TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs
211
212 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
213 TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
214 #endif
215
216 inited = true;
217}
218
219void stop_all_notes() {
220 if (!inited) {
221 audio_init();
222 }
223 voices = 0;
224 #ifdef PWM_AUDIO
225 TIMSK3 &= ~_BV(OCIE3A);
226 #else
227 TIMSK3 &= ~_BV(OCIE3A);
228 TCCR3A &= ~_BV(COM3A1);
229 #endif
230 notes = false;
231 note = false;
232 frequency = 0;
233 volume = 0;
234
235 for (int i = 0; i < 8; i++) {
236 frequencies[i] = 0;
237 volumes[i] = 0;
238 }
239}
240
241void stop_note(float freq) {
242 if (note) {
243 if (!inited) {
244 audio_init();
245 }
246 #ifdef PWM_AUDIO
247 freq = freq / SAMPLE_RATE;
248 #endif
249 for (int i = 7; i >= 0; i--) {
250 if (frequencies[i] == freq) {
251 frequencies[i] = 0;
252 volumes[i] = 0;
253 for (int j = i; (j < 7); j++) {
254 frequencies[j] = frequencies[j+1];
255 frequencies[j+1] = 0;
256 volumes[j] = volumes[j+1];
257 volumes[j+1] = 0;
258 }
259 break;
260 }
261 }
262 voices--;
263 if (voices < 0)
264 voices = 0;
265 if (voice_place >= voices) {
266 voice_place = 0;
267 }
268 if (voices == 0) {
269 #ifdef PWM_AUDIO
270 TIMSK3 &= ~_BV(OCIE3A);
271 #else
272 TIMSK3 &= ~_BV(OCIE3A);
273 TCCR3A &= ~_BV(COM3A1);
274 #endif
275 frequency = 0;
276 volume = 0;
277 note = false;
278 }
279 }
280}
281
282#ifdef VIBRATO_ENABLE
283
284float mod(float a, int b)
285{
286 float r = fmod(a, b);
287 return r < 0 ? r + b : r;
288}
289
290float vibrato(float average_freq) {
291 #ifdef VIBRATO_STRENGTH_ENABLE
292 float vibrated_freq = average_freq * pow(VIBRATO_LUT[(int)vibrato_counter], vibrato_strength);
293 #else
294 float vibrated_freq = average_freq * VIBRATO_LUT[(int)vibrato_counter];
295 #endif
296 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0/average_freq)), VIBRATO_LUT_LENGTH);
297 return vibrated_freq;
298}
299
300#endif
301
302ISR(TIMER3_COMPA_vect) {
303 if (note) {
304 #ifdef PWM_AUDIO
305 if (voices == 1) {
306 // SINE
307 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2;
308
309 // SQUARE
310 // if (((int)place) >= 1024){
311 // OCR4A = 0xFF >> 2;
312 // } else {
313 // OCR4A = 0x00;
314 // }
315
316 // SAWTOOTH
317 // OCR4A = (int)place / 4;
318
319 // TRIANGLE
320 // if (((int)place) >= 1024) {
321 // OCR4A = (int)place / 2;
322 // } else {
323 // OCR4A = 2048 - (int)place / 2;
324 // }
325
326 place += frequency;
327
328 if (place >= SINE_LENGTH)
329 place -= SINE_LENGTH;
330
331 } else {
332 int sum = 0;
333 for (int i = 0; i < voices; i++) {
334 // SINE
335 sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2;
336
337 // SQUARE
338 // if (((int)places[i]) >= 1024){
339 // sum += 0xFF >> 2;
340 // } else {
341 // sum += 0x00;
342 // }
343
344 places[i] += frequencies[i];
345
346 if (places[i] >= SINE_LENGTH)
347 places[i] -= SINE_LENGTH;
348 }
349 OCR4A = sum;
350 }
351 #else
352 if (voices > 0) {
353 float freq;
354 if (polyphony_rate > 0) {
355 if (voices > 1) {
356 voice_place %= voices;
357 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
358 voice_place = (voice_place + 1) % voices;
359 place = 0.0;
360 }
361 }
362 #ifdef VIBRATO_ENABLE
363 if (vibrato_strength > 0) {
364 freq = vibrato(frequencies[voice_place]);
365 } else {
366 #else
367 {
368 #endif
369 freq = frequencies[voice_place];
370 }
371 } else {
372 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) {
373 frequency = frequency * pow(2, 440/frequency/12/2);
374 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) {
375 frequency = frequency * pow(2, -440/frequency/12/2);
376 } else {
377 frequency = frequencies[voices - 1];
378 }
379
380
381 #ifdef VIBRATO_ENABLE
382 if (vibrato_strength > 0) {
383 freq = vibrato(frequency);
384 } else {
385 #else
386 {
387 #endif
388 freq = frequency;
389 }
390 }
391
392 if (envelope_index < 65535) {
393 envelope_index++;
394 }
395 freq = voice_envelope(freq);
396
397 if (freq < 30.517578125)
398 freq = 30.52;
399 ICR3 = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
400 OCR3A = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
401 }
402 #endif
403 }
404
405 // SAMPLE
406 // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]);
407
408 // place_int++;
409
410 // if (place_int >= sample_length)
411 // if (repeat)
412 // place_int -= sample_length;
413 // else
414 // TIMSK3 &= ~_BV(OCIE3A);
415
416
417 if (notes) {
418 #ifdef PWM_AUDIO
419 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0;
420
421 place += note_frequency;
422 if (place >= SINE_LENGTH)
423 place -= SINE_LENGTH;
424 #else
425 if (note_frequency > 0) {
426 float freq;
427
428 #ifdef VIBRATO_ENABLE
429 if (vibrato_strength > 0) {
430 freq = vibrato(note_frequency);
431 } else {
432 #else
433 {
434 #endif
435 freq = note_frequency;
436 }
437
438 if (envelope_index < 65535) {
439 envelope_index++;
440 }
441 freq = voice_envelope(freq);
442
443 ICR3 = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
444 OCR3A = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
445 } else {
446 ICR3 = 0;
447 OCR3A = 0;
448 }
449 #endif
450
451
452 note_position++;
453 bool end_of_note = false;
454 if (ICR3 > 0)
455 end_of_note = (note_position >= (note_length / ICR3 * 0xFFFF));
456 else
457 end_of_note = (note_position >= (note_length * 0x7FF));
458 if (end_of_note) {
459 current_note++;
460 if (current_note >= notes_count) {
461 if (notes_repeat) {
462 current_note = 0;
463 } else {
464 #ifdef PWM_AUDIO
465 TIMSK3 &= ~_BV(OCIE3A);
466 #else
467 TIMSK3 &= ~_BV(OCIE3A);
468 TCCR3A &= ~_BV(COM3A1);
469 #endif
470 notes = false;
471 return;
472 }
473 }
474 if (!note_resting && (notes_rest > 0)) {
475 note_resting = true;
476 note_frequency = 0;
477 note_length = notes_rest;
478 current_note--;
479 } else {
480 note_resting = false;
481 #ifdef PWM_AUDIO
482 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
483 note_length = (*notes_pointer)[current_note][1] * (note_tempo / 100);
484 #else
485 envelope_index = 0;
486 note_frequency = (*notes_pointer)[current_note][0];
487 note_length = ((*notes_pointer)[current_note][1] / 4) * (note_tempo / 100);
488 #endif
489 }
490 note_position = 0;
491 }
492
493 }
494
495 if (!audio_config.enable) {
496 notes = false;
497 note = false;
498 }
499}
500
501void play_note(float freq, int vol) {
502
503 if (!inited) {
504 audio_init();
505 }
506
507if (audio_config.enable && voices < 8) {
508 TIMSK3 &= ~_BV(OCIE3A);
509 // Cancel notes if notes are playing
510 if (notes)
511 stop_all_notes();
512 note = true;
513 envelope_index = 0;
514 #ifdef PWM_AUDIO
515 freq = freq / SAMPLE_RATE;
516 #endif
517 if (freq > 0) {
518 frequencies[voices] = freq;
519 volumes[voices] = vol;
520 voices++;
521 }
522
523 #ifdef PWM_AUDIO
524 TIMSK3 |= _BV(OCIE3A);
525 #else
526 TIMSK3 |= _BV(OCIE3A);
527 TCCR3A |= _BV(COM3A1);
528 #endif
529}
530
531}
532
533void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) {
534
535 if (!inited) {
536 audio_init();
537 }
538
539if (audio_config.enable) {
540 TIMSK3 &= ~_BV(OCIE3A);
541 // Cancel note if a note is playing
542 if (note)
543 stop_all_notes();
544 notes = true;
545
546 notes_pointer = np;
547 notes_count = n_count;
548 notes_repeat = n_repeat;
549 notes_rest = n_rest;
550
551 place = 0;
552 current_note = 0;
553 #ifdef PWM_AUDIO
554 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
555 note_length = (*notes_pointer)[current_note][1] * (note_tempo / 100);
556 #else
557 note_frequency = (*notes_pointer)[current_note][0];
558 note_length = ((*notes_pointer)[current_note][1] / 4) * (note_tempo / 100);
559 #endif
560 note_position = 0;
561
562
563 #ifdef PWM_AUDIO
564 TIMSK3 |= _BV(OCIE3A);
565 #else
566 TIMSK3 |= _BV(OCIE3A);
567 TCCR3A |= _BV(COM3A1);
568 #endif
569}
570
571}
572
573#ifdef PWM_AUDIO
574void play_sample(uint8_t * s, uint16_t l, bool r) {
575 if (!inited) {
576 audio_init();
577 }
578
579 if (audio_config.enable) {
580 TIMSK3 &= ~_BV(OCIE3A);
581 stop_all_notes();
582 place_int = 0;
583 sample = s;
584 sample_length = l;
585 repeat = r;
586
587 TIMSK3 |= _BV(OCIE3A);
588 }
589}
590#endif
591
592//------------------------------------------------------------------------------
593// Override these functions in your keymap file to play different tunes on
594// startup and bootloader jump
595__attribute__ ((weak))
596void play_startup_tone()
597{
598}
599
600
601
602__attribute__ ((weak))
603void play_goodbye_tone()
604{
605
606}
607//------------------------------------------------------------------------------