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