diff options
Diffstat (limited to 'quantum/audio/audio_avr.c')
-rw-r--r-- | quantum/audio/audio_avr.c | 812 |
1 files changed, 0 insertions, 812 deletions
diff --git a/quantum/audio/audio_avr.c b/quantum/audio/audio_avr.c deleted file mode 100644 index 1bac43bb4..000000000 --- a/quantum/audio/audio_avr.c +++ /dev/null | |||
@@ -1,812 +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 | |||
17 | #include <stdio.h> | ||
18 | #include <string.h> | ||
19 | //#include <math.h> | ||
20 | #if defined(__AVR__) | ||
21 | # include <avr/pgmspace.h> | ||
22 | # include <avr/interrupt.h> | ||
23 | # include <avr/io.h> | ||
24 | #endif | ||
25 | #include "print.h" | ||
26 | #include "audio.h" | ||
27 | #include "keymap.h" | ||
28 | #include "wait.h" | ||
29 | |||
30 | #include "eeconfig.h" | ||
31 | |||
32 | #define CPU_PRESCALER 8 | ||
33 | |||
34 | // ----------------------------------------------------------------------------- | ||
35 | // Timer Abstractions | ||
36 | // ----------------------------------------------------------------------------- | ||
37 | |||
38 | // Currently we support timers 1 and 3 used at the sime time, channels A-C, | ||
39 | // pins PB5, PB6, PB7, PC4, PC5, and PC6 | ||
40 | #if defined(C6_AUDIO) | ||
41 | # define CPIN_AUDIO | ||
42 | # define CPIN_SET_DIRECTION DDRC |= _BV(PORTC6); | ||
43 | # define INIT_AUDIO_COUNTER_3 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); | ||
44 | # define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A) | ||
45 | # define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A) | ||
46 | # define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1); | ||
47 | # define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0)); | ||
48 | # define TIMER_3_PERIOD ICR3 | ||
49 | # define TIMER_3_DUTY_CYCLE OCR3A | ||
50 | # define TIMER3_AUDIO_vect TIMER3_COMPA_vect | ||
51 | #endif | ||
52 | #if defined(C5_AUDIO) | ||
53 | # define CPIN_AUDIO | ||
54 | # define CPIN_SET_DIRECTION DDRC |= _BV(PORTC5); | ||
55 | # define INIT_AUDIO_COUNTER_3 TCCR3A = (0 << COM3B1) | (0 << COM3B0) | (1 << WGM31) | (0 << WGM30); | ||
56 | # define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3B) | ||
57 | # define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3B) | ||
58 | # define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3B1); | ||
59 | # define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3B1) | _BV(COM3B0)); | ||
60 | # define TIMER_3_PERIOD ICR3 | ||
61 | # define TIMER_3_DUTY_CYCLE OCR3B | ||
62 | # define TIMER3_AUDIO_vect TIMER3_COMPB_vect | ||
63 | #endif | ||
64 | #if defined(C4_AUDIO) | ||
65 | # define CPIN_AUDIO | ||
66 | # define CPIN_SET_DIRECTION DDRC |= _BV(PORTC4); | ||
67 | # define INIT_AUDIO_COUNTER_3 TCCR3A = (0 << COM3C1) | (0 << COM3C0) | (1 << WGM31) | (0 << WGM30); | ||
68 | # define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3C) | ||
69 | # define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3C) | ||
70 | # define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3C1); | ||
71 | # define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3C1) | _BV(COM3C0)); | ||
72 | # define TIMER_3_PERIOD ICR3 | ||
73 | # define TIMER_3_DUTY_CYCLE OCR3C | ||
74 | # define TIMER3_AUDIO_vect TIMER3_COMPC_vect | ||
75 | #endif | ||
76 | |||
77 | #if defined(B5_AUDIO) | ||
78 | # define BPIN_AUDIO | ||
79 | # define BPIN_SET_DIRECTION DDRB |= _BV(PORTB5); | ||
80 | # define INIT_AUDIO_COUNTER_1 TCCR1A = (0 << COM1A1) | (0 << COM1A0) | (1 << WGM11) | (0 << WGM10); | ||
81 | # define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1A) | ||
82 | # define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1A) | ||
83 | # define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1A1); | ||
84 | # define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1A1) | _BV(COM1A0)); | ||
85 | # define TIMER_1_PERIOD ICR1 | ||
86 | # define TIMER_1_DUTY_CYCLE OCR1A | ||
87 | # define TIMER1_AUDIO_vect TIMER1_COMPA_vect | ||
88 | #endif | ||
89 | #if defined(B6_AUDIO) | ||
90 | # define BPIN_AUDIO | ||
91 | # define BPIN_SET_DIRECTION DDRB |= _BV(PORTB6); | ||
92 | # define INIT_AUDIO_COUNTER_1 TCCR1A = (0 << COM1B1) | (0 << COM1B0) | (1 << WGM11) | (0 << WGM10); | ||
93 | # define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1B) | ||
94 | # define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1B) | ||
95 | # define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1B1); | ||
96 | # define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1B1) | _BV(COM1B0)); | ||
97 | # define TIMER_1_PERIOD ICR1 | ||
98 | # define TIMER_1_DUTY_CYCLE OCR1B | ||
99 | # define TIMER1_AUDIO_vect TIMER1_COMPB_vect | ||
100 | #endif | ||
101 | #if defined(B7_AUDIO) | ||
102 | # define BPIN_AUDIO | ||
103 | # define BPIN_SET_DIRECTION DDRB |= _BV(PORTB7); | ||
104 | # define INIT_AUDIO_COUNTER_1 TCCR1A = (0 << COM1C1) | (0 << COM1C0) | (1 << WGM11) | (0 << WGM10); | ||
105 | # define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1C) | ||
106 | # define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1C) | ||
107 | # define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1C1); | ||
108 | # define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1C1) | _BV(COM1C0)); | ||
109 | # define TIMER_1_PERIOD ICR1 | ||
110 | # define TIMER_1_DUTY_CYCLE OCR1C | ||
111 | # define TIMER1_AUDIO_vect TIMER1_COMPC_vect | ||
112 | #endif | ||
113 | |||
114 | #if !defined(BPIN_AUDIO) && !defined(CPIN_AUDIO) | ||
115 | # error "Audio feature enabled, but no suitable pin selected - see docs/feature_audio.md under the AVR settings for available options." | ||
116 | #endif | ||
117 | |||
118 | // ----------------------------------------------------------------------------- | ||
119 | |||
120 | int voices = 0; | ||
121 | int voice_place = 0; | ||
122 | float frequency = 0; | ||
123 | float frequency_alt = 0; | ||
124 | int volume = 0; | ||
125 | long position = 0; | ||
126 | |||
127 | float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
128 | int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
129 | bool sliding = false; | ||
130 | |||
131 | float place = 0; | ||
132 | |||
133 | uint8_t* sample; | ||
134 | uint16_t sample_length = 0; | ||
135 | |||
136 | bool playing_notes = false; | ||
137 | bool playing_note = false; | ||
138 | float note_frequency = 0; | ||
139 | float note_length = 0; | ||
140 | uint8_t note_tempo = TEMPO_DEFAULT; | ||
141 | float note_timbre = TIMBRE_DEFAULT; | ||
142 | uint16_t note_position = 0; | ||
143 | float (*notes_pointer)[][2]; | ||
144 | uint16_t notes_count; | ||
145 | bool notes_repeat; | ||
146 | bool note_resting = false; | ||
147 | |||
148 | uint16_t current_note = 0; | ||
149 | uint8_t rest_counter = 0; | ||
150 | |||
151 | #ifdef VIBRATO_ENABLE | ||
152 | float vibrato_counter = 0; | ||
153 | float vibrato_strength = .5; | ||
154 | float vibrato_rate = 0.125; | ||
155 | #endif | ||
156 | |||
157 | float polyphony_rate = 0; | ||
158 | |||
159 | static bool audio_initialized = false; | ||
160 | |||
161 | audio_config_t audio_config; | ||
162 | |||
163 | uint16_t envelope_index = 0; | ||
164 | bool glissando = true; | ||
165 | |||
166 | #ifndef STARTUP_SONG | ||
167 | # define STARTUP_SONG SONG(STARTUP_SOUND) | ||
168 | #endif | ||
169 | #ifndef AUDIO_ON_SONG | ||
170 | # define AUDIO_ON_SONG SONG(AUDIO_ON_SOUND) | ||
171 | #endif | ||
172 | #ifndef AUDIO_OFF_SONG | ||
173 | # define AUDIO_OFF_SONG SONG(AUDIO_OFF_SOUND) | ||
174 | #endif | ||
175 | float startup_song[][2] = STARTUP_SONG; | ||
176 | float audio_on_song[][2] = AUDIO_ON_SONG; | ||
177 | float audio_off_song[][2] = AUDIO_OFF_SONG; | ||
178 | |||
179 | void audio_init() { | ||
180 | // Check EEPROM | ||
181 | if (!eeconfig_is_enabled()) { | ||
182 | eeconfig_init(); | ||
183 | } | ||
184 | audio_config.raw = eeconfig_read_audio(); | ||
185 | |||
186 | if (!audio_initialized) { | ||
187 | // Set audio ports as output | ||
188 | #ifdef CPIN_AUDIO | ||
189 | CPIN_SET_DIRECTION | ||
190 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
191 | #endif | ||
192 | #ifdef BPIN_AUDIO | ||
193 | BPIN_SET_DIRECTION | ||
194 | DISABLE_AUDIO_COUNTER_1_ISR; | ||
195 | #endif | ||
196 | |||
197 | // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers TCCR3A/TCCR3B, TCCR1A/TCCR1B | ||
198 | // Compare Output Mode (COM3An and COM1An) = 0b00 = Normal port operation | ||
199 | // OC3A -- PC6 | ||
200 | // OC3B -- PC5 | ||
201 | // OC3C -- PC4 | ||
202 | // OC1A -- PB5 | ||
203 | // OC1B -- PB6 | ||
204 | // OC1C -- PB7 | ||
205 | |||
206 | // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14. Period = ICR3, Duty Cycle OCR3A) | ||
207 | // OCR3A - PC6 | ||
208 | // OCR3B - PC5 | ||
209 | // OCR3C - PC4 | ||
210 | // OCR1A - PB5 | ||
211 | // OCR1B - PB6 | ||
212 | // OCR1C - PB7 | ||
213 | |||
214 | // Clock Select (CS3n) = 0b010 = Clock / 8 | ||
215 | #ifdef CPIN_AUDIO | ||
216 | INIT_AUDIO_COUNTER_3 | ||
217 | TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); | ||
218 | TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (440 * CPU_PRESCALER)); | ||
219 | TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (440 * CPU_PRESCALER)) * note_timbre); | ||
220 | #endif | ||
221 | #ifdef BPIN_AUDIO | ||
222 | INIT_AUDIO_COUNTER_1 | ||
223 | TCCR1B = (1 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10); | ||
224 | TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (440 * CPU_PRESCALER)); | ||
225 | TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (440 * CPU_PRESCALER)) * note_timbre); | ||
226 | #endif | ||
227 | |||
228 | audio_initialized = true; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | void audio_startup() { | ||
233 | if (audio_config.enable) { | ||
234 | PLAY_SONG(startup_song); | ||
235 | } | ||
236 | } | ||
237 | |||
238 | void stop_all_notes() { | ||
239 | dprintf("audio stop all notes"); | ||
240 | |||
241 | if (!audio_initialized) { | ||
242 | audio_init(); | ||
243 | } | ||
244 | voices = 0; | ||
245 | |||
246 | #ifdef CPIN_AUDIO | ||
247 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
248 | DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||
249 | #endif | ||
250 | |||
251 | #ifdef BPIN_AUDIO | ||
252 | DISABLE_AUDIO_COUNTER_1_ISR; | ||
253 | DISABLE_AUDIO_COUNTER_1_OUTPUT; | ||
254 | #endif | ||
255 | |||
256 | playing_notes = false; | ||
257 | playing_note = false; | ||
258 | frequency = 0; | ||
259 | frequency_alt = 0; | ||
260 | volume = 0; | ||
261 | |||
262 | for (uint8_t i = 0; i < 8; i++) { | ||
263 | frequencies[i] = 0; | ||
264 | volumes[i] = 0; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | void stop_note(float freq) { | ||
269 | dprintf("audio stop note freq=%d", (int)freq); | ||
270 | |||
271 | if (playing_note) { | ||
272 | if (!audio_initialized) { | ||
273 | audio_init(); | ||
274 | } | ||
275 | for (int i = 7; i >= 0; i--) { | ||
276 | if (frequencies[i] == freq) { | ||
277 | frequencies[i] = 0; | ||
278 | volumes[i] = 0; | ||
279 | for (int j = i; (j < 7); j++) { | ||
280 | frequencies[j] = frequencies[j + 1]; | ||
281 | frequencies[j + 1] = 0; | ||
282 | volumes[j] = volumes[j + 1]; | ||
283 | volumes[j + 1] = 0; | ||
284 | } | ||
285 | break; | ||
286 | } | ||
287 | } | ||
288 | voices--; | ||
289 | if (voices < 0) voices = 0; | ||
290 | if (voice_place >= voices) { | ||
291 | voice_place = 0; | ||
292 | } | ||
293 | if (voices == 0) { | ||
294 | #ifdef CPIN_AUDIO | ||
295 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
296 | DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||
297 | #endif | ||
298 | #ifdef BPIN_AUDIO | ||
299 | DISABLE_AUDIO_COUNTER_1_ISR; | ||
300 | DISABLE_AUDIO_COUNTER_1_OUTPUT; | ||
301 | #endif | ||
302 | frequency = 0; | ||
303 | frequency_alt = 0; | ||
304 | volume = 0; | ||
305 | playing_note = false; | ||
306 | } | ||
307 | } | ||
308 | } | ||
309 | |||
310 | #ifdef VIBRATO_ENABLE | ||
311 | |||
312 | float mod(float a, int b) { | ||
313 | float r = fmod(a, b); | ||
314 | return r < 0 ? r + b : r; | ||
315 | } | ||
316 | |||
317 | float vibrato(float average_freq) { | ||
318 | # ifdef VIBRATO_STRENGTH_ENABLE | ||
319 | float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength); | ||
320 | # else | ||
321 | float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter]; | ||
322 | # endif | ||
323 | vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0 / average_freq)), VIBRATO_LUT_LENGTH); | ||
324 | return vibrated_freq; | ||
325 | } | ||
326 | |||
327 | #endif | ||
328 | |||
329 | #ifdef CPIN_AUDIO | ||
330 | ISR(TIMER3_AUDIO_vect) { | ||
331 | float freq; | ||
332 | |||
333 | if (playing_note) { | ||
334 | if (voices > 0) { | ||
335 | # ifdef BPIN_AUDIO | ||
336 | float freq_alt = 0; | ||
337 | if (voices > 1) { | ||
338 | if (polyphony_rate == 0) { | ||
339 | if (glissando) { | ||
340 | if (frequency_alt != 0 && frequency_alt < frequencies[voices - 2] && frequency_alt < frequencies[voices - 2] * pow(2, -440 / frequencies[voices - 2] / 12 / 2)) { | ||
341 | frequency_alt = frequency_alt * pow(2, 440 / frequency_alt / 12 / 2); | ||
342 | } else if (frequency_alt != 0 && frequency_alt > frequencies[voices - 2] && frequency_alt > frequencies[voices - 2] * pow(2, 440 / frequencies[voices - 2] / 12 / 2)) { | ||
343 | frequency_alt = frequency_alt * pow(2, -440 / frequency_alt / 12 / 2); | ||
344 | } else { | ||
345 | frequency_alt = frequencies[voices - 2]; | ||
346 | } | ||
347 | } else { | ||
348 | frequency_alt = frequencies[voices - 2]; | ||
349 | } | ||
350 | |||
351 | # ifdef VIBRATO_ENABLE | ||
352 | if (vibrato_strength > 0) { | ||
353 | freq_alt = vibrato(frequency_alt); | ||
354 | } else { | ||
355 | freq_alt = frequency_alt; | ||
356 | } | ||
357 | # else | ||
358 | freq_alt = frequency_alt; | ||
359 | # endif | ||
360 | } | ||
361 | |||
362 | if (envelope_index < 65535) { | ||
363 | envelope_index++; | ||
364 | } | ||
365 | |||
366 | freq_alt = voice_envelope(freq_alt); | ||
367 | |||
368 | if (freq_alt < 30.517578125) { | ||
369 | freq_alt = 30.52; | ||
370 | } | ||
371 | |||
372 | TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq_alt * CPU_PRESCALER)); | ||
373 | TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq_alt * CPU_PRESCALER)) * note_timbre); | ||
374 | } | ||
375 | # endif | ||
376 | |||
377 | if (polyphony_rate > 0) { | ||
378 | if (voices > 1) { | ||
379 | voice_place %= voices; | ||
380 | if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { | ||
381 | voice_place = (voice_place + 1) % voices; | ||
382 | place = 0.0; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | # ifdef VIBRATO_ENABLE | ||
387 | if (vibrato_strength > 0) { | ||
388 | freq = vibrato(frequencies[voice_place]); | ||
389 | } else { | ||
390 | freq = frequencies[voice_place]; | ||
391 | } | ||
392 | # else | ||
393 | freq = frequencies[voice_place]; | ||
394 | # endif | ||
395 | } else { | ||
396 | if (glissando) { | ||
397 | if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) { | ||
398 | frequency = frequency * pow(2, 440 / frequency / 12 / 2); | ||
399 | } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) { | ||
400 | frequency = frequency * pow(2, -440 / frequency / 12 / 2); | ||
401 | } else { | ||
402 | frequency = frequencies[voices - 1]; | ||
403 | } | ||
404 | } else { | ||
405 | frequency = frequencies[voices - 1]; | ||
406 | } | ||
407 | |||
408 | # ifdef VIBRATO_ENABLE | ||
409 | if (vibrato_strength > 0) { | ||
410 | freq = vibrato(frequency); | ||
411 | } else { | ||
412 | freq = frequency; | ||
413 | } | ||
414 | # else | ||
415 | freq = frequency; | ||
416 | # endif | ||
417 | } | ||
418 | |||
419 | if (envelope_index < 65535) { | ||
420 | envelope_index++; | ||
421 | } | ||
422 | |||
423 | freq = voice_envelope(freq); | ||
424 | |||
425 | if (freq < 30.517578125) { | ||
426 | freq = 30.52; | ||
427 | } | ||
428 | |||
429 | TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||
430 | TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); | ||
431 | } | ||
432 | } | ||
433 | |||
434 | if (playing_notes) { | ||
435 | if (note_frequency > 0) { | ||
436 | # ifdef VIBRATO_ENABLE | ||
437 | if (vibrato_strength > 0) { | ||
438 | freq = vibrato(note_frequency); | ||
439 | } else { | ||
440 | freq = note_frequency; | ||
441 | } | ||
442 | # else | ||
443 | freq = note_frequency; | ||
444 | # endif | ||
445 | |||
446 | if (envelope_index < 65535) { | ||
447 | envelope_index++; | ||
448 | } | ||
449 | freq = voice_envelope(freq); | ||
450 | |||
451 | TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||
452 | TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); | ||
453 | } else { | ||
454 | TIMER_3_PERIOD = 0; | ||
455 | TIMER_3_DUTY_CYCLE = 0; | ||
456 | } | ||
457 | |||
458 | note_position++; | ||
459 | bool end_of_note = false; | ||
460 | if (TIMER_3_PERIOD > 0) { | ||
461 | if (!note_resting) | ||
462 | end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF - 1)); | ||
463 | else | ||
464 | end_of_note = (note_position >= (note_length)); | ||
465 | } else { | ||
466 | end_of_note = (note_position >= (note_length)); | ||
467 | } | ||
468 | |||
469 | if (end_of_note) { | ||
470 | current_note++; | ||
471 | if (current_note >= notes_count) { | ||
472 | if (notes_repeat) { | ||
473 | current_note = 0; | ||
474 | } else { | ||
475 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
476 | DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||
477 | playing_notes = false; | ||
478 | return; | ||
479 | } | ||
480 | } | ||
481 | if (!note_resting) { | ||
482 | note_resting = true; | ||
483 | current_note--; | ||
484 | if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) { | ||
485 | note_frequency = 0; | ||
486 | note_length = 1; | ||
487 | } else { | ||
488 | note_frequency = (*notes_pointer)[current_note][0]; | ||
489 | note_length = 1; | ||
490 | } | ||
491 | } else { | ||
492 | note_resting = false; | ||
493 | envelope_index = 0; | ||
494 | note_frequency = (*notes_pointer)[current_note][0]; | ||
495 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | ||
496 | } | ||
497 | |||
498 | note_position = 0; | ||
499 | } | ||
500 | } | ||
501 | |||
502 | if (!audio_config.enable) { | ||
503 | playing_notes = false; | ||
504 | playing_note = false; | ||
505 | } | ||
506 | } | ||
507 | #endif | ||
508 | |||
509 | #ifdef BPIN_AUDIO | ||
510 | ISR(TIMER1_AUDIO_vect) { | ||
511 | # if defined(BPIN_AUDIO) && !defined(CPIN_AUDIO) | ||
512 | float freq = 0; | ||
513 | |||
514 | if (playing_note) { | ||
515 | if (voices > 0) { | ||
516 | if (polyphony_rate > 0) { | ||
517 | if (voices > 1) { | ||
518 | voice_place %= voices; | ||
519 | if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { | ||
520 | voice_place = (voice_place + 1) % voices; | ||
521 | place = 0.0; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | # ifdef VIBRATO_ENABLE | ||
526 | if (vibrato_strength > 0) { | ||
527 | freq = vibrato(frequencies[voice_place]); | ||
528 | } else { | ||
529 | freq = frequencies[voice_place]; | ||
530 | } | ||
531 | # else | ||
532 | freq = frequencies[voice_place]; | ||
533 | # endif | ||
534 | } else { | ||
535 | if (glissando) { | ||
536 | if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440 / frequencies[voices - 1] / 12 / 2)) { | ||
537 | frequency = frequency * pow(2, 440 / frequency / 12 / 2); | ||
538 | } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440 / frequencies[voices - 1] / 12 / 2)) { | ||
539 | frequency = frequency * pow(2, -440 / frequency / 12 / 2); | ||
540 | } else { | ||
541 | frequency = frequencies[voices - 1]; | ||
542 | } | ||
543 | } else { | ||
544 | frequency = frequencies[voices - 1]; | ||
545 | } | ||
546 | |||
547 | # ifdef VIBRATO_ENABLE | ||
548 | if (vibrato_strength > 0) { | ||
549 | freq = vibrato(frequency); | ||
550 | } else { | ||
551 | freq = frequency; | ||
552 | } | ||
553 | # else | ||
554 | freq = frequency; | ||
555 | # endif | ||
556 | } | ||
557 | |||
558 | if (envelope_index < 65535) { | ||
559 | envelope_index++; | ||
560 | } | ||
561 | |||
562 | freq = voice_envelope(freq); | ||
563 | |||
564 | if (freq < 30.517578125) { | ||
565 | freq = 30.52; | ||
566 | } | ||
567 | |||
568 | TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||
569 | TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); | ||
570 | } | ||
571 | } | ||
572 | |||
573 | if (playing_notes) { | ||
574 | if (note_frequency > 0) { | ||
575 | # ifdef VIBRATO_ENABLE | ||
576 | if (vibrato_strength > 0) { | ||
577 | freq = vibrato(note_frequency); | ||
578 | } else { | ||
579 | freq = note_frequency; | ||
580 | } | ||
581 | # else | ||
582 | freq = note_frequency; | ||
583 | # endif | ||
584 | |||
585 | if (envelope_index < 65535) { | ||
586 | envelope_index++; | ||
587 | } | ||
588 | freq = voice_envelope(freq); | ||
589 | |||
590 | TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||
591 | TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); | ||
592 | } else { | ||
593 | TIMER_1_PERIOD = 0; | ||
594 | TIMER_1_DUTY_CYCLE = 0; | ||
595 | } | ||
596 | |||
597 | note_position++; | ||
598 | bool end_of_note = false; | ||
599 | if (TIMER_1_PERIOD > 0) { | ||
600 | if (!note_resting) | ||
601 | end_of_note = (note_position >= (note_length / TIMER_1_PERIOD * 0xFFFF - 1)); | ||
602 | else | ||
603 | end_of_note = (note_position >= (note_length)); | ||
604 | } else { | ||
605 | end_of_note = (note_position >= (note_length)); | ||
606 | } | ||
607 | |||
608 | if (end_of_note) { | ||
609 | current_note++; | ||
610 | if (current_note >= notes_count) { | ||
611 | if (notes_repeat) { | ||
612 | current_note = 0; | ||
613 | } else { | ||
614 | DISABLE_AUDIO_COUNTER_1_ISR; | ||
615 | DISABLE_AUDIO_COUNTER_1_OUTPUT; | ||
616 | playing_notes = false; | ||
617 | return; | ||
618 | } | ||
619 | } | ||
620 | if (!note_resting) { | ||
621 | note_resting = true; | ||
622 | current_note--; | ||
623 | if ((*notes_pointer)[current_note][0] == (*notes_pointer)[current_note + 1][0]) { | ||
624 | note_frequency = 0; | ||
625 | note_length = 1; | ||
626 | } else { | ||
627 | note_frequency = (*notes_pointer)[current_note][0]; | ||
628 | note_length = 1; | ||
629 | } | ||
630 | } else { | ||
631 | note_resting = false; | ||
632 | envelope_index = 0; | ||
633 | note_frequency = (*notes_pointer)[current_note][0]; | ||
634 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | ||
635 | } | ||
636 | |||
637 | note_position = 0; | ||
638 | } | ||
639 | } | ||
640 | |||
641 | if (!audio_config.enable) { | ||
642 | playing_notes = false; | ||
643 | playing_note = false; | ||
644 | } | ||
645 | # endif | ||
646 | } | ||
647 | #endif | ||
648 | |||
649 | void play_note(float freq, int vol) { | ||
650 | dprintf("audio play note freq=%d vol=%d", (int)freq, vol); | ||
651 | |||
652 | if (!audio_initialized) { | ||
653 | audio_init(); | ||
654 | } | ||
655 | |||
656 | if (audio_config.enable && voices < 8) { | ||
657 | #ifdef CPIN_AUDIO | ||
658 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
659 | #endif | ||
660 | #ifdef BPIN_AUDIO | ||
661 | DISABLE_AUDIO_COUNTER_1_ISR; | ||
662 | #endif | ||
663 | |||
664 | // Cancel notes if notes are playing | ||
665 | if (playing_notes) stop_all_notes(); | ||
666 | |||
667 | playing_note = true; | ||
668 | |||
669 | envelope_index = 0; | ||
670 | |||
671 | if (freq > 0) { | ||
672 | frequencies[voices] = freq; | ||
673 | volumes[voices] = vol; | ||
674 | voices++; | ||
675 | } | ||
676 | |||
677 | #ifdef CPIN_AUDIO | ||
678 | ENABLE_AUDIO_COUNTER_3_ISR; | ||
679 | ENABLE_AUDIO_COUNTER_3_OUTPUT; | ||
680 | #endif | ||
681 | #ifdef BPIN_AUDIO | ||
682 | # ifdef CPIN_AUDIO | ||
683 | if (voices > 1) { | ||
684 | ENABLE_AUDIO_COUNTER_1_ISR; | ||
685 | ENABLE_AUDIO_COUNTER_1_OUTPUT; | ||
686 | } | ||
687 | # else | ||
688 | ENABLE_AUDIO_COUNTER_1_ISR; | ||
689 | ENABLE_AUDIO_COUNTER_1_OUTPUT; | ||
690 | # endif | ||
691 | #endif | ||
692 | } | ||
693 | } | ||
694 | |||
695 | void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat) { | ||
696 | if (!audio_initialized) { | ||
697 | audio_init(); | ||
698 | } | ||
699 | |||
700 | if (audio_config.enable) { | ||
701 | #ifdef CPIN_AUDIO | ||
702 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
703 | #endif | ||
704 | #ifdef BPIN_AUDIO | ||
705 | DISABLE_AUDIO_COUNTER_1_ISR; | ||
706 | #endif | ||
707 | |||
708 | // Cancel note if a note is playing | ||
709 | if (playing_note) stop_all_notes(); | ||
710 | |||
711 | playing_notes = true; | ||
712 | |||
713 | notes_pointer = np; | ||
714 | notes_count = n_count; | ||
715 | notes_repeat = n_repeat; | ||
716 | |||
717 | place = 0; | ||
718 | current_note = 0; | ||
719 | |||
720 | note_frequency = (*notes_pointer)[current_note][0]; | ||
721 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | ||
722 | note_position = 0; | ||
723 | |||
724 | #ifdef CPIN_AUDIO | ||
725 | ENABLE_AUDIO_COUNTER_3_ISR; | ||
726 | ENABLE_AUDIO_COUNTER_3_OUTPUT; | ||
727 | #endif | ||
728 | #ifdef BPIN_AUDIO | ||
729 | # ifndef CPIN_AUDIO | ||
730 | ENABLE_AUDIO_COUNTER_1_ISR; | ||
731 | ENABLE_AUDIO_COUNTER_1_OUTPUT; | ||
732 | # endif | ||
733 | #endif | ||
734 | } | ||
735 | } | ||
736 | |||
737 | bool is_playing_notes(void) { return playing_notes; } | ||
738 | |||
739 | bool is_audio_on(void) { return (audio_config.enable != 0); } | ||
740 | |||
741 | void audio_toggle(void) { | ||
742 | audio_config.enable ^= 1; | ||
743 | eeconfig_update_audio(audio_config.raw); | ||
744 | if (audio_config.enable) audio_on_user(); | ||
745 | } | ||
746 | |||
747 | void audio_on(void) { | ||
748 | audio_config.enable = 1; | ||
749 | eeconfig_update_audio(audio_config.raw); | ||
750 | audio_on_user(); | ||
751 | PLAY_SONG(audio_on_song); | ||
752 | } | ||
753 | |||
754 | void audio_off(void) { | ||
755 | PLAY_SONG(audio_off_song); | ||
756 | wait_ms(100); | ||
757 | stop_all_notes(); | ||
758 | audio_config.enable = 0; | ||
759 | eeconfig_update_audio(audio_config.raw); | ||
760 | } | ||
761 | |||
762 | #ifdef VIBRATO_ENABLE | ||
763 | |||
764 | // Vibrato rate functions | ||
765 | |||
766 | void set_vibrato_rate(float rate) { vibrato_rate = rate; } | ||
767 | |||
768 | void increase_vibrato_rate(float change) { vibrato_rate *= change; } | ||
769 | |||
770 | void decrease_vibrato_rate(float change) { vibrato_rate /= change; } | ||
771 | |||
772 | # ifdef VIBRATO_STRENGTH_ENABLE | ||
773 | |||
774 | void set_vibrato_strength(float strength) { vibrato_strength = strength; } | ||
775 | |||
776 | void increase_vibrato_strength(float change) { vibrato_strength *= change; } | ||
777 | |||
778 | void decrease_vibrato_strength(float change) { vibrato_strength /= change; } | ||
779 | |||
780 | # endif /* VIBRATO_STRENGTH_ENABLE */ | ||
781 | |||
782 | #endif /* VIBRATO_ENABLE */ | ||
783 | |||
784 | // Polyphony functions | ||
785 | |||
786 | void set_polyphony_rate(float rate) { polyphony_rate = rate; } | ||
787 | |||
788 | void enable_polyphony() { polyphony_rate = 5; } | ||
789 | |||
790 | void disable_polyphony() { polyphony_rate = 0; } | ||
791 | |||
792 | void increase_polyphony_rate(float change) { polyphony_rate *= change; } | ||
793 | |||
794 | void decrease_polyphony_rate(float change) { polyphony_rate /= change; } | ||
795 | |||
796 | // Timbre function | ||
797 | |||
798 | void set_timbre(float timbre) { note_timbre = timbre; } | ||
799 | |||
800 | // Tempo functions | ||
801 | |||
802 | void set_tempo(uint8_t tempo) { note_tempo = tempo; } | ||
803 | |||
804 | void decrease_tempo(uint8_t tempo_change) { note_tempo += tempo_change; } | ||
805 | |||
806 | void increase_tempo(uint8_t tempo_change) { | ||
807 | if (note_tempo - tempo_change < 10) { | ||
808 | note_tempo = 10; | ||
809 | } else { | ||
810 | note_tempo -= tempo_change; | ||
811 | } | ||
812 | } | ||