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