]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/audio.c
updates to preonic default, music mode integrated
[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
8 #include "audio.h"
9 #include "keymap_common.h"
10
11 #include "eeconfig.h"
12
13 #define PI 3.14159265
14
15 // #define PWM_AUDIO
16
17 #ifdef PWM_AUDIO
18     #include "wave.h"
19     #define SAMPLE_DIVIDER 39
20     #define SAMPLE_RATE (2000000.0/SAMPLE_DIVIDER/2048)
21     // Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap
22 #endif
23
24 void delay_us(int count) {
25   while(count--) {
26     _delay_us(1);
27   }
28 }
29
30 int voices = 0;
31 int voice_place = 0;
32 double frequency = 0;
33 int volume = 0;
34 long position = 0;
35 int duty_place = 1;
36 int duty_counter = 0;
37
38 double frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
39 int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
40 bool sliding = false;
41
42 int max = 0xFF;
43 float sum = 0;
44 int value = 128;
45 float place = 0;
46 float places[8] = {0, 0, 0, 0, 0, 0, 0, 0};
47
48 uint16_t place_int = 0;
49 bool repeat = true;
50 uint8_t * sample;
51 uint16_t sample_length = 0;
52
53
54 bool notes = false;
55 bool note = false;
56 float note_frequency = 0;
57 float note_length = 0;
58 uint16_t note_position = 0;
59 float (* notes_pointer)[][2];
60 uint8_t notes_length;
61 bool notes_repeat;
62 uint8_t current_note = 0;
63
64 audio_config_t audio_config;
65
66
67 void audio_toggle(void) {
68     audio_config.enable ^= 1;
69     eeconfig_write_audio(audio_config.raw);
70 }
71
72 void audio_on(void) {
73     audio_config.enable = 1;
74     eeconfig_write_audio(audio_config.raw);
75 }
76
77 void audio_off(void) {
78     audio_config.enable = 0;
79     eeconfig_write_audio(audio_config.raw);
80 }
81
82
83 void stop_all_notes() {
84     voices = 0;
85     #ifdef PWM_AUDIO
86         TIMSK3 &= ~_BV(OCIE3A);
87     #else
88         TIMSK3 &= ~_BV(OCIE3A);
89         TCCR3A &= ~_BV(COM3A1);
90     #endif
91     notes = false;
92     note = false;
93     frequency = 0;
94     volume = 0;
95
96     for (int i = 0; i < 8; i++) {
97         frequencies[i] = 0;
98         volumes[i] = 0;
99     }
100 }
101
102 void stop_note(double freq) {
103     if (note) {
104         #ifdef PWM_AUDIO
105             freq = freq / SAMPLE_RATE;
106         #endif
107         for (int i = 7; i >= 0; i--) {
108             if (frequencies[i] == freq) {
109                 frequencies[i] = 0;
110                 volumes[i] = 0;
111                 for (int j = i; (j < 7); j++) {
112                     frequencies[j] = frequencies[j+1];
113                     frequencies[j+1] = 0;
114                     volumes[j] = volumes[j+1];
115                     volumes[j+1] = 0;
116                 }
117             }
118         }
119         voices--;
120         if (voices < 0)
121             voices = 0;
122         if (voices == 0) {
123             #ifdef PWM_AUDIO
124                 TIMSK3 &= ~_BV(OCIE3A);
125             #else
126                 TIMSK3 &= ~_BV(OCIE3A);
127                 TCCR3A &= ~_BV(COM3A1);
128             #endif
129             frequency = 0;
130             volume = 0;
131             note = false;
132         } else {
133             double freq = frequencies[voices - 1];
134             int vol = volumes[voices - 1];
135             double starting_f = frequency;
136             if (frequency < freq) {
137                 sliding = true;
138                 for (double f = starting_f; f <= freq; f += ((freq - starting_f) / 2000.0)) {
139                     frequency = f;
140                 }
141                 sliding = false;
142             } else if (frequency > freq) {
143                 sliding = true;
144                 for (double f = starting_f; f >= freq; f -= ((starting_f - freq) / 2000.0)) {
145                     frequency = f;
146                 }
147                 sliding = false;
148             }
149             frequency = freq;
150             volume = vol;
151         }
152     }
153 }
154
155 void init_notes() {
156
157     /* check signature */
158     if (!eeconfig_is_enabled()) {
159         eeconfig_init();
160     }
161     audio_config.raw = eeconfig_read_audio();
162
163     #ifdef PWM_AUDIO
164         PLLFRQ = _BV(PDIV2);
165         PLLCSR = _BV(PLLE);
166         while(!(PLLCSR & _BV(PLOCK)));
167         PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */
168
169         /* Init a fast PWM on Timer4 */
170         TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */
171         TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */
172         OCR4A = 0;
173
174         /* Enable the OC4A output */
175         DDRC |= _BV(PORTC6);
176
177         TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs
178         
179         TCCR3A = 0x0; // Options not needed
180         TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC
181         OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback
182     #else
183         DDRC |= _BV(PORTC6);
184
185         TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs
186
187         TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
188         TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
189     #endif
190 }
191
192
193 ISR(TIMER3_COMPA_vect) {
194     if (note) {
195         #ifdef PWM_AUDIO
196             if (voices == 1) {
197                 // SINE
198                 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2;
199             
200                 // SQUARE
201                 // if (((int)place) >= 1024){
202                 //     OCR4A = 0xFF >> 2;
203                 // } else {
204                 //     OCR4A = 0x00;
205                 // }
206                 
207                 // SAWTOOTH
208                 // OCR4A = (int)place / 4;
209
210                 // TRIANGLE
211                 // if (((int)place) >= 1024) {
212                 //     OCR4A = (int)place / 2;
213                 // } else {
214                 //     OCR4A = 2048 - (int)place / 2;
215                 // }
216
217                 place += frequency;
218
219                 if (place >= SINE_LENGTH)
220                     place -= SINE_LENGTH;
221
222             } else {
223                 int sum = 0;
224                 for (int i = 0; i < voices; i++) {
225                     // SINE
226                     sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2;
227
228                     // SQUARE
229                     // if (((int)places[i]) >= 1024){
230                     //     sum += 0xFF >> 2;
231                     // } else {
232                     //     sum += 0x00;
233                     // }
234
235                     places[i] += frequencies[i];
236
237                     if (places[i] >= SINE_LENGTH)
238                         places[i] -= SINE_LENGTH;
239                 }
240                 OCR4A = sum;
241             }
242         #else
243             if (frequency > 0) {
244                 // ICR3 = (int)(((double)F_CPU) / frequency); // Set max to the period
245                 // OCR3A = (int)(((double)F_CPU) / frequency) >> 1; // Set compare to half the period
246                 voice_place %= voices;
247                 if (place > (frequencies[voice_place] / 500)) {
248                     voice_place = (voice_place + 1) % voices;
249                     place = 0.0;
250                 }
251                 ICR3 = (int)(((double)F_CPU) / frequencies[voice_place]); // Set max to the period
252                 OCR3A = (int)(((double)F_CPU) / frequencies[voice_place]) >> 1 * duty_place; // Set compare to half the period
253                 place++;
254                 // if (duty_counter > (frequencies[voice_place] / 500)) {
255                 //     duty_place = (duty_place % 3) + 1;
256                 //     duty_counter = 0;
257                 // }
258                 // duty_counter++;
259             }
260         #endif
261     }
262
263     // SAMPLE
264     // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]);
265
266     // place_int++;
267
268     // if (place_int >= sample_length)
269     //     if (repeat)
270     //         place_int -= sample_length;
271     //     else
272     //         TIMSK3 &= ~_BV(OCIE3A);
273
274
275     if (notes) {
276         #ifdef PWM_AUDIO
277             OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0;
278
279             place += note_frequency;
280             if (place >= SINE_LENGTH)
281                 place -= SINE_LENGTH;
282         #else
283             if (note_frequency > 0) {
284                 ICR3 = (int)(((double)F_CPU) / note_frequency); // Set max to the period
285                 OCR3A = (int)(((double)F_CPU) / note_frequency) >> 1; // Set compare to half the period
286             } else {
287                 ICR3 = 0;
288                 OCR3A = 0;
289             }
290         #endif
291
292
293         note_position++;
294         bool end_of_note = false;
295         if (ICR3 > 0) 
296             end_of_note = (note_position >= (note_length / ICR3 * 0xFFFF));
297         else 
298             end_of_note = (note_position >= (note_length * 0x7FF));
299         if (end_of_note) {
300             current_note++;
301             if (current_note >= notes_length) {
302                 if (notes_repeat) {
303                     current_note = 0;
304                 } else {
305                     #ifdef PWM_AUDIO
306                         TIMSK3 &= ~_BV(OCIE3A);
307                     #else
308                         TIMSK3 &= ~_BV(OCIE3A);
309                         TCCR3A &= ~_BV(COM3A1);
310                     #endif
311                     notes = false;
312                     return;
313                 }
314             }
315             #ifdef PWM_AUDIO
316                 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
317                 note_length = (*notes_pointer)[current_note][1];
318             #else
319                 note_frequency = (*notes_pointer)[current_note][0];
320                 note_length = (*notes_pointer)[current_note][1] / 4;
321             #endif
322             note_position = 0;
323         }
324
325     }
326
327     if (!audio_config.enable) {
328         notes = false;
329         note = false;
330     }
331 }
332
333 void play_notes(float (*np)[][2], uint8_t n_length, bool n_repeat) {
334
335 if (audio_config.enable) {
336
337     if (note)
338         stop_all_notes();
339     notes = true;
340
341     notes_pointer = np;
342     notes_length = n_length;
343     notes_repeat = n_repeat;
344
345     place = 0;
346     current_note = 0;
347     #ifdef PWM_AUDIO
348         note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
349         note_length = (*notes_pointer)[current_note][1];
350     #else
351         note_frequency = (*notes_pointer)[current_note][0];
352         note_length = (*notes_pointer)[current_note][1] / 4;
353     #endif
354     note_position = 0;
355
356
357     #ifdef PWM_AUDIO
358         TIMSK3 |= _BV(OCIE3A);
359     #else
360         TIMSK3 |= _BV(OCIE3A);
361         TCCR3A |= _BV(COM3A1);
362     #endif
363 }
364
365 }
366
367 void play_sample(uint8_t * s, uint16_t l, bool r) {
368
369 if (audio_config.enable) {
370
371     stop_all_notes();
372     place_int = 0;
373     sample = s;
374     sample_length = l;
375     repeat = r;
376
377     #ifdef PWM_AUDIO
378         TIMSK3 |= _BV(OCIE3A);
379     #else
380     #endif
381
382 }
383
384 }
385
386 void play_note(double freq, int vol) {
387
388 if (audio_config.enable && voices < 8) {
389
390     if (notes)
391         stop_all_notes();
392     note = true;
393     #ifdef PWM_AUDIO
394         freq = freq / SAMPLE_RATE;
395     #endif
396     if (freq > 0) {
397         if (frequency != 0) {
398             double starting_f = frequency;
399             if (frequency < freq) {
400                 for (double f = starting_f; f <= freq; f += ((freq - starting_f) / 2000.0)) {   
401                     frequency = f;
402                 }
403             } else if (frequency > freq) {
404                 for (double f = starting_f; f >= freq; f -= ((starting_f - freq) / 2000.0)) {
405                     frequency = f;
406                 }
407             }
408         }
409         frequency = freq;
410         volume = vol;
411
412         frequencies[voices] = frequency;
413         volumes[voices] = volume;
414         voices++;
415     }
416
417     #ifdef PWM_AUDIO
418         TIMSK3 |= _BV(OCIE3A);
419     #else
420         TIMSK3 |= _BV(OCIE3A);
421         TCCR3A |= _BV(COM3A1);
422     #endif
423
424 }
425
426 }