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