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