1 /* Copyright 2016 Jack Humbert
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.
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.
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/>.
19 #include <avr/pgmspace.h>
20 #include <avr/interrupt.h>
28 #define CPU_PRESCALER 8
30 // -----------------------------------------------------------------------------
32 // -----------------------------------------------------------------------------
34 // TIMSK3 - Timer/Counter #3 Interrupt Mask Register
35 // Turn on/off 3A interputs, stopping/enabling the ISR calls
37 #define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A)
38 #define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A)
42 #define ENABLE_AUDIO_COUNTER_1_ISR TIMSK1 |= _BV(OCIE1A)
43 #define DISABLE_AUDIO_COUNTER_1_ISR TIMSK1 &= ~_BV(OCIE1A)
46 // TCCR3A: Timer/Counter #3 Control Register
47 // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
50 #define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1);
51 #define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0));
55 #define ENABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A |= _BV(COM1A1);
56 #define DISABLE_AUDIO_COUNTER_1_OUTPUT TCCR1A &= ~(_BV(COM1A1) | _BV(COM1A0));
59 // Fast PWM Mode Controls
62 #define TIMER_3_PERIOD ICR3
63 #define TIMER_3_DUTY_CYCLE OCR3A
67 #define TIMER_1_PERIOD ICR1
68 #define TIMER_1_DUTY_CYCLE OCR1A
72 // -----------------------------------------------------------------------------
81 float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
82 int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
88 uint16_t sample_length = 0;
90 bool playing_notes = false;
91 bool playing_note = false;
92 float note_frequency = 0;
93 float note_length = 0;
94 uint8_t note_tempo = TEMPO_DEFAULT;
95 float note_timbre = TIMBRE_DEFAULT;
96 uint16_t note_position = 0;
97 float (* notes_pointer)[][2];
101 bool note_resting = false;
103 uint8_t current_note = 0;
104 uint8_t rest_counter = 0;
106 #ifdef VIBRATO_ENABLE
107 float vibrato_counter = 0;
108 float vibrato_strength = .5;
109 float vibrato_rate = 0.125;
112 float polyphony_rate = 0;
114 static bool audio_initialized = false;
116 audio_config_t audio_config;
118 uint16_t envelope_index = 0;
119 bool glissando = true;
125 if (!eeconfig_is_enabled())
129 audio_config.raw = eeconfig_read_audio();
131 // Set port PC6 (OC3A and /OC4A) as output
137 PORTC &= ~_BV(PORTC6);
144 PORTB &= ~_BV(PORTB5);
148 DISABLE_AUDIO_COUNTER_3_ISR;
152 DISABLE_AUDIO_COUNTER_1_ISR;
155 // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
156 // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
157 // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A)
158 // Clock Select (CS3n) = 0b010 = Clock / 8
161 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
162 TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
166 TCCR1A = (0 << COM1A1) | (0 << COM1A0) | (1 << WGM11) | (0 << WGM10);
167 TCCR1B = (1 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10);
170 audio_initialized = true;
173 void stop_all_notes()
175 dprintf("audio stop all notes");
177 if (!audio_initialized) {
184 DISABLE_AUDIO_COUNTER_3_ISR;
185 DISABLE_AUDIO_COUNTER_3_OUTPUT;
189 DISABLE_AUDIO_COUNTER_1_ISR;
190 DISABLE_AUDIO_COUNTER_1_OUTPUT;
193 playing_notes = false;
194 playing_note = false;
198 for (uint8_t i = 0; i < 8; i++)
205 void stop_note(float freq)
207 dprintf("audio stop note freq=%d", (int)freq);
210 if (!audio_initialized) {
213 for (int i = 7; i >= 0; i--) {
214 if (frequencies[i] == freq) {
217 for (int j = i; (j < 7); j++) {
218 frequencies[j] = frequencies[j+1];
219 frequencies[j+1] = 0;
220 volumes[j] = volumes[j+1];
229 if (voice_place >= voices) {
234 DISABLE_AUDIO_COUNTER_3_ISR;
235 DISABLE_AUDIO_COUNTER_3_OUTPUT;
238 DISABLE_AUDIO_COUNTER_1_ISR;
239 DISABLE_AUDIO_COUNTER_1_OUTPUT;
243 playing_note = false;
248 #ifdef VIBRATO_ENABLE
250 float mod(float a, int b)
252 float r = fmod(a, b);
253 return r < 0 ? r + b : r;
256 float vibrato(float average_freq) {
257 #ifdef VIBRATO_STRENGTH_ENABLE
258 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
260 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
262 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0/average_freq)), VIBRATO_LUT_LENGTH);
263 return vibrated_freq;
269 ISR(TIMER3_COMPA_vect)
275 if (polyphony_rate > 0) {
277 voice_place %= voices;
278 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
279 voice_place = (voice_place + 1) % voices;
284 #ifdef VIBRATO_ENABLE
285 if (vibrato_strength > 0) {
286 freq = vibrato(frequencies[voice_place]);
288 freq = frequencies[voice_place];
291 freq = frequencies[voice_place];
295 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) {
296 frequency = frequency * pow(2, 440/frequency/12/2);
297 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) {
298 frequency = frequency * pow(2, -440/frequency/12/2);
300 frequency = frequencies[voices - 1];
303 frequency = frequencies[voices - 1];
306 #ifdef VIBRATO_ENABLE
307 if (vibrato_strength > 0) {
308 freq = vibrato(frequency);
317 if (envelope_index < 65535) {
321 freq = voice_envelope(freq);
323 if (freq < 30.517578125) {
327 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
328 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
333 if (note_frequency > 0) {
334 #ifdef VIBRATO_ENABLE
335 if (vibrato_strength > 0) {
336 freq = vibrato(note_frequency);
338 freq = note_frequency;
341 freq = note_frequency;
344 if (envelope_index < 65535) {
347 freq = voice_envelope(freq);
349 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
350 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
353 TIMER_3_DUTY_CYCLE = 0;
357 bool end_of_note = false;
358 if (TIMER_3_PERIOD > 0) {
359 end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF));
361 end_of_note = (note_position >= (note_length * 0x7FF));
366 if (current_note >= notes_count) {
370 DISABLE_AUDIO_COUNTER_3_ISR;
371 DISABLE_AUDIO_COUNTER_3_OUTPUT;
372 playing_notes = false;
376 if (!note_resting && (notes_rest > 0)) {
379 note_length = notes_rest;
382 note_resting = false;
384 note_frequency = (*notes_pointer)[current_note][0];
385 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
392 if (!audio_config.enable) {
393 playing_notes = false;
394 playing_note = false;
400 ISR(TIMER1_COMPA_vect)
406 if (polyphony_rate > 0) {
408 voice_place %= voices;
409 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
410 voice_place = (voice_place + 1) % voices;
415 #ifdef VIBRATO_ENABLE
416 if (vibrato_strength > 0) {
417 freq = vibrato(frequencies[voice_place]);
419 freq = frequencies[voice_place];
422 freq = frequencies[voice_place];
426 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) {
427 frequency = frequency * pow(2, 440/frequency/12/2);
428 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) {
429 frequency = frequency * pow(2, -440/frequency/12/2);
431 frequency = frequencies[voices - 1];
434 frequency = frequencies[voices - 1];
437 #ifdef VIBRATO_ENABLE
438 if (vibrato_strength > 0) {
439 freq = vibrato(frequency);
448 if (envelope_index < 65535) {
452 freq = voice_envelope(freq);
454 if (freq < 30.517578125) {
458 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
459 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
464 if (note_frequency > 0) {
465 #ifdef VIBRATO_ENABLE
466 if (vibrato_strength > 0) {
467 freq = vibrato(note_frequency);
469 freq = note_frequency;
472 freq = note_frequency;
475 if (envelope_index < 65535) {
478 freq = voice_envelope(freq);
480 TIMER_1_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
481 TIMER_1_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
484 TIMER_1_DUTY_CYCLE = 0;
488 bool end_of_note = false;
489 if (TIMER_1_PERIOD > 0) {
490 end_of_note = (note_position >= (note_length / TIMER_1_PERIOD * 0xFFFF));
492 end_of_note = (note_position >= (note_length * 0x7FF));
497 if (current_note >= notes_count) {
501 DISABLE_AUDIO_COUNTER_1_ISR;
502 DISABLE_AUDIO_COUNTER_1_OUTPUT;
503 playing_notes = false;
507 if (!note_resting && (notes_rest > 0)) {
510 note_length = notes_rest;
513 note_resting = false;
515 note_frequency = (*notes_pointer)[current_note][0];
516 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
523 if (!audio_config.enable) {
524 playing_notes = false;
525 playing_note = false;
530 void play_note(float freq, int vol) {
532 dprintf("audio play note freq=%d vol=%d", (int)freq, vol);
534 if (!audio_initialized) {
538 if (audio_config.enable && voices < 8) {
540 DISABLE_AUDIO_COUNTER_3_ISR;
543 DISABLE_AUDIO_COUNTER_1_ISR;
546 // Cancel notes if notes are playing
555 frequencies[voices] = freq;
556 volumes[voices] = vol;
561 ENABLE_AUDIO_COUNTER_3_ISR;
562 ENABLE_AUDIO_COUNTER_3_OUTPUT;
565 ENABLE_AUDIO_COUNTER_1_ISR;
566 ENABLE_AUDIO_COUNTER_1_OUTPUT;
572 void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest)
575 if (!audio_initialized) {
579 if (audio_config.enable) {
582 DISABLE_AUDIO_COUNTER_3_ISR;
585 DISABLE_AUDIO_COUNTER_1_ISR;
588 // Cancel note if a note is playing
592 playing_notes = true;
595 notes_count = n_count;
596 notes_repeat = n_repeat;
602 note_frequency = (*notes_pointer)[current_note][0];
603 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
608 ENABLE_AUDIO_COUNTER_3_ISR;
609 ENABLE_AUDIO_COUNTER_3_OUTPUT;
612 ENABLE_AUDIO_COUNTER_1_ISR;
613 ENABLE_AUDIO_COUNTER_1_OUTPUT;
619 bool is_playing_notes(void) {
620 return playing_notes;
623 bool is_audio_on(void) {
624 return (audio_config.enable != 0);
627 void audio_toggle(void) {
628 audio_config.enable ^= 1;
629 eeconfig_update_audio(audio_config.raw);
630 if (audio_config.enable)
634 void audio_on(void) {
635 audio_config.enable = 1;
636 eeconfig_update_audio(audio_config.raw);
640 void audio_off(void) {
641 audio_config.enable = 0;
642 eeconfig_update_audio(audio_config.raw);
645 #ifdef VIBRATO_ENABLE
647 // Vibrato rate functions
649 void set_vibrato_rate(float rate) {
653 void increase_vibrato_rate(float change) {
654 vibrato_rate *= change;
657 void decrease_vibrato_rate(float change) {
658 vibrato_rate /= change;
661 #ifdef VIBRATO_STRENGTH_ENABLE
663 void set_vibrato_strength(float strength) {
664 vibrato_strength = strength;
667 void increase_vibrato_strength(float change) {
668 vibrato_strength *= change;
671 void decrease_vibrato_strength(float change) {
672 vibrato_strength /= change;
675 #endif /* VIBRATO_STRENGTH_ENABLE */
677 #endif /* VIBRATO_ENABLE */
679 // Polyphony functions
681 void set_polyphony_rate(float rate) {
682 polyphony_rate = rate;
685 void enable_polyphony() {
689 void disable_polyphony() {
693 void increase_polyphony_rate(float change) {
694 polyphony_rate *= change;
697 void decrease_polyphony_rate(float change) {
698 polyphony_rate /= change;
703 void set_timbre(float timbre) {
704 note_timbre = timbre;
709 void set_tempo(uint8_t tempo) {
713 void decrease_tempo(uint8_t tempo_change) {
714 note_tempo += tempo_change;
717 void increase_tempo(uint8_t tempo_change) {
718 if (note_tempo - tempo_change < 10) {
721 note_tempo -= tempo_change;