mirror of
				https://github.com/mfulz/qmk_firmware.git
				synced 2025-10-30 21:02:32 +01:00 
			
		
		
		
	Clarified audio.c (#302)
* Updated personal layouts * tweaked personal * Nightly - Audio Cleanup Refactored the LUTs. Abstracted some of the registers out of audio to use more functional names. Split audio into audio and audio_pwm. WIP * nightly - collapsed code * Added check for note playing to LEDs
This commit is contained in:
		
							parent
							
								
									2c070163ff
								
							
						
					
					
						commit
						83e1cc241e
					
				| @ -158,4 +158,9 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
| //#define NO_ACTION_MACRO
 | ||||
| //#define NO_ACTION_FUNCTION
 | ||||
| 
 | ||||
| 
 | ||||
| //#define VIBRATO_ENABLE
 | ||||
| //#define VIBRATO_STRENGTH_ENABLE
 | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -11,8 +11,8 @@ | ||||
| #define LAYER_QWERTY         0 | ||||
| #define LAYER_COLEMAK        1 | ||||
| #define LAYER_DVORAK         2 | ||||
| #define LAYER_LOWER          3 | ||||
| #define LAYER_RAISE          4 | ||||
| #define LAYER_RAISE          3 | ||||
| #define LAYER_LOWER          4 | ||||
| #define LAYER_FUNCTION       5 | ||||
| #define LAYER_MOUSE          6 | ||||
| #define LAYER_MUSIC          7 | ||||
| @ -21,8 +21,8 @@ | ||||
| #define MACRO_QWERTY         0 | ||||
| #define MACRO_COLEMAK        1 | ||||
| #define MACRO_DVORAK         2 | ||||
| #define MACRO_LOWER          3 | ||||
| #define MACRO_RAISE          4 | ||||
| #define MACRO_RAISE          3 | ||||
| #define MACRO_LOWER          4 | ||||
| #define MACRO_FUNCTION       5 | ||||
| #define MACRO_MOUSE          6 | ||||
| #define MACRO_TIMBRE_1       7 | ||||
| @ -42,8 +42,8 @@ | ||||
| #define M_QWRTY             M(MACRO_QWERTY) | ||||
| #define M_COLMK             M(MACRO_COLEMAK) | ||||
| #define M_DVORK             M(MACRO_DVORAK) | ||||
| #define M_LOWER             M(MACRO_LOWER) | ||||
| #define M_RAISE             M(MACRO_RAISE) | ||||
| #define M_LOWER             M(MACRO_LOWER) | ||||
| #define M_FUNCT             M(MACRO_FUNCTION) | ||||
| #define M_MOUSE             M(MACRO_MOUSE) | ||||
| #define TIMBR_1             M(MACRO_TIMBRE_1) | ||||
| @ -148,23 +148,22 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | ||||
|   { KC_LCTL, KC_LGUI, M_FUNCT, KC_LALT, M_RAISE, KC_SPC,  KC_SPC,  M_LOWER, KC_RALT, KC_RGUI, KC_MENU, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT  }, | ||||
|  }, | ||||
| 
 | ||||
|  [LAYER_RAISE]        = { /* RAISED */ | ||||
|   { KC_TILD, KC_PSCR, KC_PAUS, KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_F7,   KC_F8,   KC_F9,   KC_F10,  KC_F11,  KC_F12,  ________________  }, | ||||
|   { _______, KC_F1,   KC_F2,   KC_F3,   KC_F4,   _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_INS   }, | ||||
|   { _______, KC_F5,   KC_F6,   KC_F7,   KC_F8,   _______, _______, _______, _______, _______, _______, _______, ________________, KC_HOME  }, | ||||
|   { _______, KC_F9,   KC_F10,  KC_F11,  KC_F12,  _______, _______, _______, _______, _______, _______, ________________, _______, KC_END   }, | ||||
|   { _______, _______, _______, _______, _______, ________________, _______, _______, _______, _______, _______, _______, _______, _______  }, | ||||
|  }, | ||||
| 
 | ||||
|  [LAYER_LOWER]        = { /* LOWERED */ | ||||
|   { KC_GRV,  KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_F7,   KC_F8,   KC_F9,   KC_F10,  KC_F11,  KC_F12,  ________________  }, | ||||
|   { _______, _______, _______, _______, SC_CCLS, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_INS   }, | ||||
|   { _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, ________________, KC_HOME  }, | ||||
|   { _______, SC_REDO, _______, _______, _______, _______, _______, _______, _______, _______, _______, ________________, _______, KC_END   }, | ||||
|   { _______, KC_F13,  KC_F14,  KC_F15,  KC_F16,  _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_INS   }, | ||||
|   { _______, KC_F17,  KC_F18,  KC_F19,  KC_F20,  _______, _______, _______, _______, _______, _______, _______, ________________, KC_HOME  }, | ||||
|   { _______, KC_F21,  KC_F22,  KC_F23,  KC_F24,  _______, _______, _______, _______, _______, _______, ________________, _______, KC_END   }, | ||||
|   { _______, _______, _______, _______, _______, KC_BSPC, KC_BSPC, _______, _______, _______, _______, _______, _______, _______, _______  }, | ||||
|  }, | ||||
| 
 | ||||
|  [LAYER_RAISE]        = { /* RAISED */ | ||||
|   { KC_TILD, KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_F7,   KC_F8,   KC_F9,   KC_F10,  KC_F11,  KC_F12,  ________________  }, | ||||
|   { _______, _______, _______, _______, SC_ACLS, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_INS   }, | ||||
|   { _______, SC_SELA, SC_SAVE, _______, _______, _______, _______, _______, _______, _______, _______, _______, ________________, KC_HOME  }, | ||||
|   { _______, SC_UNDO, SC_CUT,  SC_COPY, SC_PSTE, _______, _______, _______, _______, _______, _______, ________________, _______, KC_END   }, | ||||
|   { _______, _______, _______, _______, _______, ________________, _______, _______, _______, _______, _______, _______, _______, _______  }, | ||||
|  }, | ||||
| 
 | ||||
|  [LAYER_FUNCTION]     = { /* FUNCTION */ | ||||
|   { KC_NLCK, KC_F1,   KC_F2,   KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_F7,   KC_F8,   KC_F9,   KC_F10,  KC_F11,  KC_F12,  ________________  }, | ||||
|   { KC_SLCK, KC_F13,  KC_F14,  KC_F15,  KC_F16,  KC_F17,  KC_F18,  KC_F19,  KC_F20,  KC_F21,  KC_F22,  KC_F23,  KC_F24,  _______, KC_PAUS  }, | ||||
| @ -281,19 +280,6 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|         case MACRO_LOWER: | ||||
|             if (record->event.pressed) | ||||
|             { | ||||
|                 layer_on(LAYER_LOWER); | ||||
|                 update_tri_layer(LAYER_LOWER, LAYER_RAISE, LAYER_ADJUST); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 layer_off(LAYER_LOWER); | ||||
|                 update_tri_layer(LAYER_LOWER, LAYER_RAISE, LAYER_ADJUST); | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|         case MACRO_RAISE: | ||||
|             if (record->event.pressed) | ||||
|             { | ||||
| @ -307,6 +293,19 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|         case MACRO_LOWER: | ||||
|             if (record->event.pressed) | ||||
|             { | ||||
|                 layer_on(LAYER_LOWER); | ||||
|                 update_tri_layer(LAYER_LOWER, LAYER_RAISE, LAYER_ADJUST); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 layer_off(LAYER_LOWER); | ||||
|                 update_tri_layer(LAYER_LOWER, LAYER_RAISE, LAYER_ADJUST); | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|         case MACRO_FUNCTION: | ||||
|             if (record->event.pressed) | ||||
|             { | ||||
| @ -468,6 +467,8 @@ void led_set_user(uint8_t usb_led) | ||||
| 
 | ||||
|     _delay_ms(10); // gets rid of tick
 | ||||
| 
 | ||||
| 	if (!is_playing_notes()) | ||||
| 	{ | ||||
| 	    if ((usb_led & (1<<USB_LED_CAPS_LOCK)) && !(old_usb_led & (1<<USB_LED_CAPS_LOCK))) | ||||
| 	    { | ||||
| 	            // If CAPS LK LED is turning on...
 | ||||
| @ -498,6 +499,8 @@ void led_set_user(uint8_t usb_led) | ||||
| 	            // If SCROLL LED is turning off...
 | ||||
| 	            PLAY_NOTE_ARRAY(tone_scroll_off, false, LEGATO); | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
|     old_usb_led = usb_led; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -73,7 +73,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| 
 | ||||
| /* disable debug print */ | ||||
| //#define NO_DEBUG
 | ||||
| #define NO_DEBUG | ||||
| 
 | ||||
| /* disable print */ | ||||
| //#define NO_PRINT
 | ||||
|  | ||||
| @ -96,7 +96,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | ||||
| 
 | ||||
|  [LAYER_QWERTY]       = { /* QWERTY */ | ||||
|   { KC_TAB,  KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,    KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,    KC_BSPC   }, | ||||
|   { KC_BSPC, KC_A,    KC_S,    KC_D,    KC_F,    KC_G,    KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN, KC_QUOT  }, | ||||
|   { KC_ESC,  KC_A,    KC_S,    KC_D,    KC_F,    KC_G,    KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN, KC_QUOT  }, | ||||
|   { KC_LSFT, KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_N,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_ENT   }, | ||||
|   { KC_LCTL, KC_LGUI, M_FUNCT, KC_LALT, M_RAISE, KC_SPC,  KC_SPC,  M_LOWER, KC_UP,   KC_DOWN, KC_LEFT, KC_RGHT  }, | ||||
|  }, | ||||
| @ -115,7 +115,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | ||||
| 
 | ||||
|  [LAYER_COLEMAK]      = { /* COLEMAK */ | ||||
|   { KC_TAB,  KC_Q,    KC_W,    KC_F,    KC_P,    KC_G,    KC_J,    KC_L,    KC_U,    KC_Y,    KC_SCLN, KC_ESC   }, | ||||
|   { KC_ESC,  KC_A,    KC_R,    KC_S,    KC_T,    KC_D,    KC_H,    KC_N,    KC_E,    KC_I,    KC_O,    KC_QUOT  }, | ||||
|   { KC_BSPC, KC_A,    KC_R,    KC_S,    KC_T,    KC_D,    KC_H,    KC_N,    KC_E,    KC_I,    KC_O,    KC_QUOT  }, | ||||
|   { KC_LSFT, KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_K,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_ENT   }, | ||||
|   { KC_LCTL, KC_LGUI, M_FUNCT, KC_LALT, M_RAISE, KC_SPC,  KC_SPC,  M_LOWER, KC_UP,   KC_DOWN, KC_LEFT, KC_RGHT  }, | ||||
|  }, | ||||
|  | ||||
| @ -4,6 +4,7 @@ EXTRAKEY_ENABLE  = yes # Audio control and System control(+450) | ||||
| CONSOLE_ENABLE   = yes # Console for debug(+400) | ||||
| COMMAND_ENABLE   = yes # Commands for debug and configuration | ||||
| NKRO_ENABLE      = yes # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work | ||||
| BACKLIGHT_ENABLE = no  # Enable keyboard backlight functionality | ||||
| MIDI_ENABLE      = no  # MIDI controls | ||||
| AUDIO_ENABLE     = no  # Audio output on port C6 | ||||
| UNICODE_ENABLE   = no  # Unicode | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <math.h> | ||||
| //#include <math.h>
 | ||||
| #include <avr/pgmspace.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include <avr/io.h> | ||||
| @ -10,30 +10,28 @@ | ||||
| 
 | ||||
| #include "eeconfig.h" | ||||
| 
 | ||||
| #ifdef VIBRATO_ENABLE | ||||
|     #include "vibrato_lut.h" | ||||
| #endif | ||||
| 
 | ||||
| #define PI 3.14159265 | ||||
| 
 | ||||
| #define CPU_PRESCALER 8 | ||||
| 
 | ||||
| #ifdef PWM_AUDIO | ||||
|     #include "wave.h" | ||||
|     #define SAMPLE_DIVIDER 39 | ||||
|     #define SAMPLE_RATE (2000000.0/SAMPLE_DIVIDER/2048) | ||||
|     // Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap
 | ||||
| // -----------------------------------------------------------------------------
 | ||||
| // Timer Abstractions
 | ||||
| // -----------------------------------------------------------------------------
 | ||||
| 
 | ||||
|     float places[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||||
|     uint16_t place_int = 0; | ||||
|     bool repeat = true; | ||||
| #endif | ||||
| // TIMSK3 - Timer/Counter #3 Interrupt Mask Register
 | ||||
| // Turn on/off 3A interputs, stopping/enabling the ISR calls
 | ||||
| #define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A) | ||||
| #define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A) | ||||
| 
 | ||||
| // TCCR3A: Timer/Counter #3 Control Register
 | ||||
| // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
 | ||||
| #define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1); | ||||
| #define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0)); | ||||
| 
 | ||||
| // Fast PWM Mode Controls
 | ||||
| #define TIMER_3_PERIOD     ICR3 | ||||
| #define TIMER_3_DUTY_CYCLE OCR3A | ||||
| 
 | ||||
| // -----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| void delay_us(int count) { | ||||
|   while(count--) { | ||||
|     _delay_us(1); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int voices = 0; | ||||
| int voice_place = 0; | ||||
| @ -45,19 +43,16 @@ float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||||
| int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||||
| bool sliding = false; | ||||
| 
 | ||||
| int max = 0xFF; | ||||
| float sum = 0; | ||||
| float place = 0; | ||||
| 
 | ||||
| uint8_t * sample; | ||||
| uint16_t sample_length = 0; | ||||
| // float freq = 0;
 | ||||
| 
 | ||||
| bool notes = false; | ||||
| bool note = false; | ||||
| bool     playing_notes = false; | ||||
| bool     playing_note = false; | ||||
| float    note_frequency = 0; | ||||
| float    note_length = 0; | ||||
| float note_tempo = TEMPO_DEFAULT; | ||||
| uint8_t  note_tempo = TEMPO_DEFAULT; | ||||
| float    note_timbre = TIMBRE_DEFAULT; | ||||
| uint16_t note_position = 0; | ||||
| float (* notes_pointer)[][2]; | ||||
| @ -77,12 +72,308 @@ float vibrato_rate = 0.125; | ||||
| 
 | ||||
| float polyphony_rate = 0; | ||||
| 
 | ||||
| bool inited = false; | ||||
| static bool audio_initialized = false; | ||||
| 
 | ||||
| audio_config_t audio_config; | ||||
| 
 | ||||
| uint16_t envelope_index = 0; | ||||
| 
 | ||||
| void audio_init() | ||||
| { | ||||
| 
 | ||||
|     // Check EEPROM
 | ||||
|     if (!eeconfig_is_enabled()) | ||||
|     { | ||||
|         eeconfig_init(); | ||||
|     } | ||||
|     audio_config.raw = eeconfig_read_audio(); | ||||
| 
 | ||||
| 	// Set port PC6 (OC3A and /OC4A) as output
 | ||||
|     DDRC |= _BV(PORTC6); | ||||
| 
 | ||||
|     DISABLE_AUDIO_COUNTER_3_ISR; | ||||
| 
 | ||||
| 	// TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
 | ||||
| 	// Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
 | ||||
| 	// Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A)
 | ||||
| 	// Clock Select (CS3n) = 0b010 = Clock / 8
 | ||||
|     TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); | ||||
|     TCCR3B = (1 << WGM33)  | (1 << WGM32)  | (0 << CS32)  | (1 << CS31) | (0 << CS30); | ||||
| 
 | ||||
|     audio_initialized = true; | ||||
| } | ||||
| 
 | ||||
| void stop_all_notes() | ||||
| { | ||||
|     if (!audio_initialized) { | ||||
|         audio_init(); | ||||
|     } | ||||
|     voices = 0; | ||||
| 
 | ||||
|     DISABLE_AUDIO_COUNTER_3_ISR; | ||||
|     DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||||
| 
 | ||||
|     playing_notes = false; | ||||
|     playing_note = false; | ||||
|     frequency = 0; | ||||
|     volume = 0; | ||||
| 
 | ||||
|     for (uint8_t i = 0; i < 8; i++) | ||||
|     { | ||||
|         frequencies[i] = 0; | ||||
|         volumes[i] = 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void stop_note(float freq) | ||||
| { | ||||
|     if (playing_note) { | ||||
|         if (!audio_initialized) { | ||||
|             audio_init(); | ||||
|         } | ||||
|         for (int i = 7; i >= 0; i--) { | ||||
|             if (frequencies[i] == freq) { | ||||
|                 frequencies[i] = 0; | ||||
|                 volumes[i] = 0; | ||||
|                 for (int j = i; (j < 7); j++) { | ||||
|                     frequencies[j] = frequencies[j+1]; | ||||
|                     frequencies[j+1] = 0; | ||||
|                     volumes[j] = volumes[j+1]; | ||||
|                     volumes[j+1] = 0; | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         voices--; | ||||
|         if (voices < 0) | ||||
|             voices = 0; | ||||
|         if (voice_place >= voices) { | ||||
|             voice_place = 0; | ||||
|         } | ||||
|         if (voices == 0) { | ||||
|             DISABLE_AUDIO_COUNTER_3_ISR; | ||||
|             DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||||
|             frequency = 0; | ||||
|             volume = 0; | ||||
|             playing_note = false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #ifdef VIBRATO_ENABLE | ||||
| 
 | ||||
| float mod(float a, int b) | ||||
| { | ||||
|     float r = fmod(a, b); | ||||
|     return r < 0 ? r + b : r; | ||||
| } | ||||
| 
 | ||||
| float vibrato(float average_freq) { | ||||
|     #ifdef VIBRATO_STRENGTH_ENABLE | ||||
|         float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength); | ||||
|     #else | ||||
|         float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter]; | ||||
|     #endif | ||||
|     vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0/average_freq)), VIBRATO_LUT_LENGTH); | ||||
|     return vibrated_freq; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| ISR(TIMER3_COMPA_vect) | ||||
| { | ||||
| 	float freq; | ||||
| 
 | ||||
| 	if (playing_note) { | ||||
| 		if (voices > 0) { | ||||
| 			if (polyphony_rate > 0) { | ||||
| 				if (voices > 1) { | ||||
| 					voice_place %= voices; | ||||
| 					if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { | ||||
| 						voice_place = (voice_place + 1) % voices; | ||||
| 						place = 0.0; | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				#ifdef VIBRATO_ENABLE | ||||
| 					if (vibrato_strength > 0) { | ||||
| 						freq = vibrato(frequencies[voice_place]); | ||||
| 					} else { | ||||
| 						freq = frequencies[voice_place]; | ||||
| 					} | ||||
| 				#else | ||||
| 					freq = frequencies[voice_place]; | ||||
| 				#endif | ||||
| 			} else { | ||||
| 				if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) { | ||||
| 					frequency = frequency * pow(2, 440/frequency/12/2); | ||||
| 				} else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) { | ||||
| 					frequency = frequency * pow(2, -440/frequency/12/2); | ||||
| 				} else { | ||||
| 					frequency = frequencies[voices - 1]; | ||||
| 				} | ||||
| 
 | ||||
| 				#ifdef VIBRATO_ENABLE | ||||
| 					if (vibrato_strength > 0) { | ||||
| 						freq = vibrato(frequency); | ||||
| 					} else { | ||||
| 						freq = frequency; | ||||
| 					} | ||||
| 				#else | ||||
| 					freq = frequency; | ||||
| 				#endif | ||||
| 			} | ||||
| 
 | ||||
| 			if (envelope_index < 65535) { | ||||
| 				envelope_index++; | ||||
| 			} | ||||
| 
 | ||||
| 			freq = voice_envelope(freq); | ||||
| 
 | ||||
| 			if (freq < 30.517578125) { | ||||
| 				freq = 30.52; | ||||
| 			} | ||||
| 
 | ||||
| 			TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||||
| 			TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (playing_notes) { | ||||
| 		if (note_frequency > 0) { | ||||
| 			#ifdef VIBRATO_ENABLE | ||||
| 				if (vibrato_strength > 0) { | ||||
| 					freq = vibrato(note_frequency); | ||||
| 				} else { | ||||
| 					freq = note_frequency; | ||||
| 				} | ||||
| 			#else | ||||
| 					freq = note_frequency; | ||||
| 			#endif | ||||
| 
 | ||||
| 			if (envelope_index < 65535) { | ||||
| 				envelope_index++; | ||||
| 			} | ||||
| 			freq = voice_envelope(freq); | ||||
| 
 | ||||
| 			TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||||
| 			TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); | ||||
| 		} else { | ||||
| 			TIMER_3_PERIOD = 0; | ||||
| 			TIMER_3_DUTY_CYCLE = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		note_position++; | ||||
| 		bool end_of_note = false; | ||||
| 		if (TIMER_3_PERIOD > 0) { | ||||
| 			end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF)); | ||||
| 		} else { | ||||
| 			end_of_note = (note_position >= (note_length * 0x7FF)); | ||||
| 		} | ||||
| 
 | ||||
| 		if (end_of_note) { | ||||
| 			current_note++; | ||||
| 			if (current_note >= notes_count) { | ||||
| 				if (notes_repeat) { | ||||
| 					current_note = 0; | ||||
| 				} else { | ||||
| 					DISABLE_AUDIO_COUNTER_3_ISR; | ||||
| 					DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||||
| 					playing_notes = false; | ||||
| 					return; | ||||
| 				} | ||||
| 			} | ||||
| 			if (!note_resting && (notes_rest > 0)) { | ||||
| 				note_resting = true; | ||||
| 				note_frequency = 0; | ||||
| 				note_length = notes_rest; | ||||
| 				current_note--; | ||||
| 			} else { | ||||
| 				note_resting = false; | ||||
| 				envelope_index = 0; | ||||
| 				note_frequency = (*notes_pointer)[current_note][0]; | ||||
| 				note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | ||||
| 			} | ||||
| 
 | ||||
| 			note_position = 0; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!audio_config.enable) { | ||||
| 		playing_notes = false; | ||||
| 		playing_note = false; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void play_note(float freq, int vol) { | ||||
| 
 | ||||
|     if (!audio_initialized) { | ||||
|         audio_init(); | ||||
|     } | ||||
| 
 | ||||
| 	if (audio_config.enable && voices < 8) { | ||||
| 	    DISABLE_AUDIO_COUNTER_3_ISR; | ||||
| 
 | ||||
| 	    // Cancel notes if notes are playing
 | ||||
| 	    if (playing_notes) | ||||
| 	        stop_all_notes(); | ||||
| 
 | ||||
| 	    playing_note = true; | ||||
| 
 | ||||
| 	    envelope_index = 0; | ||||
| 
 | ||||
| 	    if (freq > 0) { | ||||
| 	        frequencies[voices] = freq; | ||||
| 	        volumes[voices] = vol; | ||||
| 	        voices++; | ||||
| 	    } | ||||
| 
 | ||||
|         ENABLE_AUDIO_COUNTER_3_ISR; | ||||
|         ENABLE_AUDIO_COUNTER_3_OUTPUT; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) | ||||
| { | ||||
| 
 | ||||
|     if (!audio_initialized) { | ||||
|         audio_init(); | ||||
|     } | ||||
| 
 | ||||
| 	if (audio_config.enable) { | ||||
| 
 | ||||
| 	    DISABLE_AUDIO_COUNTER_3_ISR; | ||||
| 
 | ||||
| 		// Cancel note if a note is playing
 | ||||
| 	    if (playing_note) | ||||
| 	        stop_all_notes(); | ||||
| 
 | ||||
| 	    playing_notes = true; | ||||
| 
 | ||||
| 	    notes_pointer = np; | ||||
| 	    notes_count = n_count; | ||||
| 	    notes_repeat = n_repeat; | ||||
| 	    notes_rest = n_rest; | ||||
| 
 | ||||
| 	    place = 0; | ||||
| 	    current_note = 0; | ||||
| 
 | ||||
|         note_frequency = (*notes_pointer)[current_note][0]; | ||||
|         note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | ||||
| 	    note_position = 0; | ||||
| 
 | ||||
| 
 | ||||
|         ENABLE_AUDIO_COUNTER_3_ISR; | ||||
|         ENABLE_AUDIO_COUNTER_3_OUTPUT; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| bool is_playing_notes(void) { | ||||
| 	return playing_notes; | ||||
| } | ||||
| 
 | ||||
| void audio_toggle(void) { | ||||
|     audio_config.enable ^= 1; | ||||
|     eeconfig_update_audio(audio_config.raw); | ||||
| @ -99,6 +390,7 @@ void audio_off(void) { | ||||
| } | ||||
| 
 | ||||
| #ifdef VIBRATO_ENABLE | ||||
| 
 | ||||
| // Vibrato rate functions
 | ||||
| 
 | ||||
| void set_vibrato_rate(float rate) { | ||||
| @ -127,9 +419,9 @@ void decrease_vibrato_strength(float change) { | ||||
|     vibrato_strength /= change; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| #endif  /* VIBRATO_STRENGTH_ENABLE */ | ||||
| 
 | ||||
| #endif | ||||
| #endif /* VIBRATO_ENABLE */ | ||||
| 
 | ||||
| // Polyphony functions
 | ||||
| 
 | ||||
| @ -161,433 +453,22 @@ void set_timbre(float timbre) { | ||||
| 
 | ||||
| // Tempo functions
 | ||||
| 
 | ||||
| void set_tempo(float tempo) { | ||||
| void set_tempo(uint8_t tempo) { | ||||
|     note_tempo = tempo; | ||||
| } | ||||
| 
 | ||||
| void decrease_tempo(uint8_t tempo_change) { | ||||
|     note_tempo += (float) tempo_change; | ||||
|     note_tempo += tempo_change; | ||||
| } | ||||
| 
 | ||||
| void increase_tempo(uint8_t tempo_change) { | ||||
|     if (note_tempo - (float) tempo_change < 10) { | ||||
|     if (note_tempo - tempo_change < 10) { | ||||
|         note_tempo = 10; | ||||
|     } else { | ||||
|         note_tempo -= (float) tempo_change; | ||||
|         note_tempo -= tempo_change; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void audio_init() { | ||||
| 
 | ||||
|     /* check signature */ | ||||
|     if (!eeconfig_is_enabled()) { | ||||
|         eeconfig_init(); | ||||
|     } | ||||
|     audio_config.raw = eeconfig_read_audio(); | ||||
| 
 | ||||
|     #ifdef PWM_AUDIO | ||||
|         PLLFRQ = _BV(PDIV2); | ||||
|         PLLCSR = _BV(PLLE); | ||||
|         while(!(PLLCSR & _BV(PLOCK))); | ||||
|         PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */ | ||||
| 
 | ||||
|         /* Init a fast PWM on Timer4 */ | ||||
|         TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */ | ||||
|         TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */ | ||||
|         OCR4A = 0; | ||||
| 
 | ||||
|         /* Enable the OC4A output */ | ||||
|         DDRC |= _BV(PORTC6); | ||||
| 
 | ||||
|         TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs
 | ||||
| 
 | ||||
|         TCCR3A = 0x0; // Options not needed
 | ||||
|         TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC
 | ||||
|         OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback
 | ||||
|     #else | ||||
|         DDRC |= _BV(PORTC6); | ||||
| 
 | ||||
|         TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs
 | ||||
| 
 | ||||
|         TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); | ||||
|         TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); | ||||
|     #endif | ||||
| 
 | ||||
|     inited = true; | ||||
| } | ||||
| 
 | ||||
| void stop_all_notes() { | ||||
|     if (!inited) { | ||||
|         audio_init(); | ||||
|     } | ||||
|     voices = 0; | ||||
|     #ifdef PWM_AUDIO | ||||
|         TIMSK3 &= ~_BV(OCIE3A); | ||||
|     #else | ||||
|         TIMSK3 &= ~_BV(OCIE3A); | ||||
|         TCCR3A &= ~_BV(COM3A1); | ||||
|     #endif | ||||
|     notes = false; | ||||
|     note = false; | ||||
|     frequency = 0; | ||||
|     volume = 0; | ||||
| 
 | ||||
|     for (int i = 0; i < 8; i++) { | ||||
|         frequencies[i] = 0; | ||||
|         volumes[i] = 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void stop_note(float freq) { | ||||
|     if (note) { | ||||
|         if (!inited) { | ||||
|             audio_init(); | ||||
|         } | ||||
|         #ifdef PWM_AUDIO | ||||
|             freq = freq / SAMPLE_RATE; | ||||
|         #endif | ||||
|         for (int i = 7; i >= 0; i--) { | ||||
|             if (frequencies[i] == freq) { | ||||
|                 frequencies[i] = 0; | ||||
|                 volumes[i] = 0; | ||||
|                 for (int j = i; (j < 7); j++) { | ||||
|                     frequencies[j] = frequencies[j+1]; | ||||
|                     frequencies[j+1] = 0; | ||||
|                     volumes[j] = volumes[j+1]; | ||||
|                     volumes[j+1] = 0; | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         voices--; | ||||
|         if (voices < 0) | ||||
|             voices = 0; | ||||
|         if (voice_place >= voices) { | ||||
|             voice_place = 0; | ||||
|         } | ||||
|         if (voices == 0) { | ||||
|             #ifdef PWM_AUDIO | ||||
|                 TIMSK3 &= ~_BV(OCIE3A); | ||||
|             #else | ||||
|                 TIMSK3 &= ~_BV(OCIE3A); | ||||
|                 TCCR3A &= ~_BV(COM3A1); | ||||
|             #endif | ||||
|             frequency = 0; | ||||
|             volume = 0; | ||||
|             note = false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #ifdef VIBRATO_ENABLE | ||||
| 
 | ||||
| float mod(float a, int b) | ||||
| { | ||||
|     float r = fmod(a, b); | ||||
|     return r < 0 ? r + b : r; | ||||
| } | ||||
| 
 | ||||
| float vibrato(float average_freq) { | ||||
|     #ifdef VIBRATO_STRENGTH_ENABLE | ||||
|         float vibrated_freq = average_freq * pow(VIBRATO_LUT[(int)vibrato_counter], vibrato_strength); | ||||
|     #else | ||||
|         float vibrated_freq = average_freq * VIBRATO_LUT[(int)vibrato_counter]; | ||||
|     #endif | ||||
|     vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0/average_freq)), VIBRATO_LUT_LENGTH); | ||||
|     return vibrated_freq; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| ISR(TIMER3_COMPA_vect) { | ||||
|     if (note) { | ||||
|         #ifdef PWM_AUDIO | ||||
|             if (voices == 1) { | ||||
|                 // SINE
 | ||||
|                 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2; | ||||
| 
 | ||||
|                 // SQUARE
 | ||||
|                 // if (((int)place) >= 1024){
 | ||||
|                 //     OCR4A = 0xFF >> 2;
 | ||||
|                 // } else {
 | ||||
|                 //     OCR4A = 0x00;
 | ||||
|                 // }
 | ||||
| 
 | ||||
|                 // SAWTOOTH
 | ||||
|                 // OCR4A = (int)place / 4;
 | ||||
| 
 | ||||
|                 // TRIANGLE
 | ||||
|                 // if (((int)place) >= 1024) {
 | ||||
|                 //     OCR4A = (int)place / 2;
 | ||||
|                 // } else {
 | ||||
|                 //     OCR4A = 2048 - (int)place / 2;
 | ||||
|                 // }
 | ||||
| 
 | ||||
|                 place += frequency; | ||||
| 
 | ||||
|                 if (place >= SINE_LENGTH) | ||||
|                     place -= SINE_LENGTH; | ||||
| 
 | ||||
|             } else { | ||||
|                 int sum = 0; | ||||
|                 for (int i = 0; i < voices; i++) { | ||||
|                     // SINE
 | ||||
|                     sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2; | ||||
| 
 | ||||
|                     // SQUARE
 | ||||
|                     // if (((int)places[i]) >= 1024){
 | ||||
|                     //     sum += 0xFF >> 2;
 | ||||
|                     // } else {
 | ||||
|                     //     sum += 0x00;
 | ||||
|                     // }
 | ||||
| 
 | ||||
|                     places[i] += frequencies[i]; | ||||
| 
 | ||||
|                     if (places[i] >= SINE_LENGTH) | ||||
|                         places[i] -= SINE_LENGTH; | ||||
|                 } | ||||
|                 OCR4A = sum; | ||||
|             } | ||||
|         #else | ||||
|             if (voices > 0) { | ||||
|                 float freq; | ||||
|                 if (polyphony_rate > 0) {                 | ||||
|                     if (voices > 1) { | ||||
|                         voice_place %= voices; | ||||
|                         if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { | ||||
|                             voice_place = (voice_place + 1) % voices; | ||||
|                             place = 0.0; | ||||
|                         } | ||||
|                     } | ||||
|                     #ifdef VIBRATO_ENABLE | ||||
|                     if (vibrato_strength > 0) { | ||||
|                         freq = vibrato(frequencies[voice_place]); | ||||
|                     } else { | ||||
|                     #else | ||||
|                     { | ||||
|                     #endif | ||||
|                         freq = frequencies[voice_place]; | ||||
|                     }  | ||||
|                 } else { | ||||
|                     if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) { | ||||
|                         frequency = frequency * pow(2, 440/frequency/12/2); | ||||
|                     } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) { | ||||
|                         frequency = frequency * pow(2, -440/frequency/12/2); | ||||
|                     } else { | ||||
|                         frequency = frequencies[voices - 1]; | ||||
|                     } | ||||
| 
 | ||||
| 
 | ||||
|                     #ifdef VIBRATO_ENABLE | ||||
|                     if (vibrato_strength > 0) { | ||||
|                         freq = vibrato(frequency); | ||||
|                     } else { | ||||
|                     #else | ||||
|                     { | ||||
|                     #endif | ||||
|                         freq = frequency; | ||||
|                     }  | ||||
|                 } | ||||
| 
 | ||||
|                 if (envelope_index < 65535) { | ||||
|                     envelope_index++; | ||||
|                 } | ||||
|                 freq = voice_envelope(freq); | ||||
| 
 | ||||
|                 if (freq < 30.517578125) | ||||
|                     freq = 30.52; | ||||
|                 ICR3 = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
 | ||||
|                 OCR3A = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
 | ||||
|             } | ||||
|         #endif | ||||
|     } | ||||
| 
 | ||||
|     // SAMPLE
 | ||||
|     // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]);
 | ||||
| 
 | ||||
|     // place_int++;
 | ||||
| 
 | ||||
|     // if (place_int >= sample_length)
 | ||||
|     //     if (repeat)
 | ||||
|     //         place_int -= sample_length;
 | ||||
|     //     else
 | ||||
|     //         TIMSK3 &= ~_BV(OCIE3A);
 | ||||
| 
 | ||||
| 
 | ||||
|     if (notes) { | ||||
|         #ifdef PWM_AUDIO | ||||
|             OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0; | ||||
| 
 | ||||
|             place += note_frequency; | ||||
|             if (place >= SINE_LENGTH) | ||||
|                 place -= SINE_LENGTH; | ||||
|         #else | ||||
|             if (note_frequency > 0) { | ||||
|                 float freq; | ||||
| 
 | ||||
|                 #ifdef VIBRATO_ENABLE | ||||
|                 if (vibrato_strength > 0) { | ||||
|                     freq = vibrato(note_frequency); | ||||
|                 } else { | ||||
|                 #else | ||||
|                 { | ||||
|                 #endif | ||||
|                     freq = note_frequency; | ||||
|                 } | ||||
| 
 | ||||
|                 if (envelope_index < 65535) { | ||||
|                     envelope_index++; | ||||
|                 } | ||||
|                 freq = voice_envelope(freq); | ||||
| 
 | ||||
|                 ICR3 = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
 | ||||
|                 OCR3A = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
 | ||||
|             } else { | ||||
|                 ICR3 = 0; | ||||
|                 OCR3A = 0; | ||||
|             } | ||||
|         #endif | ||||
| 
 | ||||
| 
 | ||||
|         note_position++; | ||||
|         bool end_of_note = false; | ||||
|         if (ICR3 > 0) | ||||
|             end_of_note = (note_position >= (note_length / ICR3 * 0xFFFF)); | ||||
|         else | ||||
|             end_of_note = (note_position >= (note_length * 0x7FF)); | ||||
|         if (end_of_note) { | ||||
|             current_note++; | ||||
|             if (current_note >= notes_count) { | ||||
|                 if (notes_repeat) { | ||||
|                     current_note = 0; | ||||
|                 } else { | ||||
|                     #ifdef PWM_AUDIO | ||||
|                         TIMSK3 &= ~_BV(OCIE3A); | ||||
|                     #else | ||||
|                         TIMSK3 &= ~_BV(OCIE3A); | ||||
|                         TCCR3A &= ~_BV(COM3A1); | ||||
|                     #endif | ||||
|                     notes = false; | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|             if (!note_resting && (notes_rest > 0)) { | ||||
|                 note_resting = true; | ||||
|                 note_frequency = 0; | ||||
|                 note_length = notes_rest; | ||||
|                 current_note--; | ||||
|             } else { | ||||
|                 note_resting = false; | ||||
|                 #ifdef PWM_AUDIO | ||||
|                     note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE; | ||||
|                     note_length = (*notes_pointer)[current_note][1] * (note_tempo / 100); | ||||
|                 #else | ||||
|                     envelope_index = 0; | ||||
|                     note_frequency = (*notes_pointer)[current_note][0]; | ||||
|                     note_length = ((*notes_pointer)[current_note][1] / 4) * (note_tempo / 100); | ||||
|                 #endif | ||||
|             } | ||||
|             note_position = 0; | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     if (!audio_config.enable) { | ||||
|         notes = false; | ||||
|         note = false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void play_note(float freq, int vol) { | ||||
| 
 | ||||
|     if (!inited) { | ||||
|         audio_init(); | ||||
|     } | ||||
| 
 | ||||
| if (audio_config.enable && voices < 8) { | ||||
|     TIMSK3 &= ~_BV(OCIE3A); | ||||
|     // Cancel notes if notes are playing
 | ||||
|     if (notes) | ||||
|         stop_all_notes(); | ||||
|     note = true; | ||||
|     envelope_index = 0; | ||||
|     #ifdef PWM_AUDIO | ||||
|         freq = freq / SAMPLE_RATE; | ||||
|     #endif | ||||
|     if (freq > 0) { | ||||
|         frequencies[voices] = freq; | ||||
|         volumes[voices] = vol; | ||||
|         voices++; | ||||
|     } | ||||
| 
 | ||||
|     #ifdef PWM_AUDIO | ||||
|         TIMSK3 |= _BV(OCIE3A); | ||||
|     #else | ||||
|         TIMSK3 |= _BV(OCIE3A); | ||||
|         TCCR3A |= _BV(COM3A1); | ||||
|     #endif | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) { | ||||
| 
 | ||||
|     if (!inited) { | ||||
|         audio_init(); | ||||
|     } | ||||
| 
 | ||||
| if (audio_config.enable) { | ||||
|     TIMSK3 &= ~_BV(OCIE3A); | ||||
| 	// Cancel note if a note is playing
 | ||||
|     if (note) | ||||
|         stop_all_notes(); | ||||
|     notes = true; | ||||
| 
 | ||||
|     notes_pointer = np; | ||||
|     notes_count = n_count; | ||||
|     notes_repeat = n_repeat; | ||||
|     notes_rest = n_rest; | ||||
| 
 | ||||
|     place = 0; | ||||
|     current_note = 0; | ||||
|     #ifdef PWM_AUDIO | ||||
|         note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE; | ||||
|         note_length = (*notes_pointer)[current_note][1] * (note_tempo / 100); | ||||
|     #else | ||||
|         note_frequency = (*notes_pointer)[current_note][0]; | ||||
|         note_length = ((*notes_pointer)[current_note][1] / 4) * (note_tempo / 100); | ||||
|     #endif | ||||
|     note_position = 0; | ||||
| 
 | ||||
| 
 | ||||
|     #ifdef PWM_AUDIO | ||||
|         TIMSK3 |= _BV(OCIE3A); | ||||
|     #else | ||||
|         TIMSK3 |= _BV(OCIE3A); | ||||
|         TCCR3A |= _BV(COM3A1); | ||||
|     #endif | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #ifdef PWM_AUDIO | ||||
| void play_sample(uint8_t * s, uint16_t l, bool r) { | ||||
|     if (!inited) { | ||||
|         audio_init(); | ||||
|     } | ||||
| 
 | ||||
|     if (audio_config.enable) { | ||||
|         TIMSK3 &= ~_BV(OCIE3A); | ||||
|         stop_all_notes(); | ||||
|         place_int = 0; | ||||
|         sample = s; | ||||
|         sample_length = l; | ||||
|         repeat = r; | ||||
| 
 | ||||
|         TIMSK3 |= _BV(OCIE3A); | ||||
|     } | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| //------------------------------------------------------------------------------
 | ||||
| // Override these functions in your keymap file to play different tunes on
 | ||||
| @ -597,11 +478,8 @@ void play_startup_tone() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| __attribute__ ((weak)) | ||||
| void play_goodbye_tone() | ||||
| { | ||||
| 
 | ||||
| } | ||||
| //------------------------------------------------------------------------------
 | ||||
|  | ||||
| @ -56,7 +56,7 @@ void increase_polyphony_rate(float change); | ||||
| void decrease_polyphony_rate(float change); | ||||
| 
 | ||||
| void set_timbre(float timbre); | ||||
| void set_tempo(float tempo); | ||||
| void set_tempo(uint8_t tempo); | ||||
| 
 | ||||
| void increase_tempo(uint8_t tempo_change); | ||||
| void decrease_tempo(uint8_t tempo_change); | ||||
| @ -83,7 +83,11 @@ void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) | ||||
| #define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0])))) | ||||
| #define PLAY_NOTE_ARRAY(note_array, note_repeat, note_rest_style) play_notes(¬e_array, NOTE_ARRAY_SIZE((note_array)), (note_repeat), (note_rest_style)); | ||||
| 
 | ||||
| 
 | ||||
| bool is_playing_notes(void); | ||||
| void play_goodbye_tone(void); | ||||
| void play_startup_tone(void); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										643
									
								
								quantum/audio/audio_pwm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										643
									
								
								quantum/audio/audio_pwm.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,643 @@ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| //#include <math.h>
 | ||||
| #include <avr/pgmspace.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include <avr/io.h> | ||||
| #include "print.h" | ||||
| #include "audio.h" | ||||
| #include "keymap_common.h" | ||||
| 
 | ||||
| #include "eeconfig.h" | ||||
| 
 | ||||
| #define PI 3.14159265 | ||||
| 
 | ||||
| #define CPU_PRESCALER 8 | ||||
| 
 | ||||
| 
 | ||||
| // Timer Abstractions
 | ||||
| 
 | ||||
| // TIMSK3 - Timer/Counter #3 Interrupt Mask Register
 | ||||
| // Turn on/off 3A interputs, stopping/enabling the ISR calls
 | ||||
| #define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A) | ||||
| #define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A) | ||||
| 
 | ||||
| 
 | ||||
| // TCCR3A: Timer/Counter #3 Control Register
 | ||||
| // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
 | ||||
| #define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1); | ||||
| #define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0)); | ||||
| 
 | ||||
| 
 | ||||
| #define NOTE_PERIOD ICR3 | ||||
| #define NOTE_DUTY_CYCLE OCR3A | ||||
| 
 | ||||
| 
 | ||||
| #ifdef PWM_AUDIO | ||||
|     #include "wave.h" | ||||
|     #define SAMPLE_DIVIDER 39 | ||||
|     #define SAMPLE_RATE (2000000.0/SAMPLE_DIVIDER/2048) | ||||
|     // Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap
 | ||||
| 
 | ||||
|     float places[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||||
|     uint16_t place_int = 0; | ||||
|     bool repeat = true; | ||||
| #endif | ||||
| 
 | ||||
| void delay_us(int count) { | ||||
|   while(count--) { | ||||
|     _delay_us(1); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int voices = 0; | ||||
| int voice_place = 0; | ||||
| float frequency = 0; | ||||
| int volume = 0; | ||||
| long position = 0; | ||||
| 
 | ||||
| float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||||
| int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||||
| bool sliding = false; | ||||
| 
 | ||||
| float place = 0; | ||||
| 
 | ||||
| uint8_t * sample; | ||||
| uint16_t sample_length = 0; | ||||
| // float freq = 0;
 | ||||
| 
 | ||||
| bool     playing_notes = false; | ||||
| bool     playing_note = false; | ||||
| float    note_frequency = 0; | ||||
| float    note_length = 0; | ||||
| uint8_t  note_tempo = TEMPO_DEFAULT; | ||||
| float    note_timbre = TIMBRE_DEFAULT; | ||||
| uint16_t note_position = 0; | ||||
| float (* notes_pointer)[][2]; | ||||
| uint16_t notes_count; | ||||
| bool     notes_repeat; | ||||
| float    notes_rest; | ||||
| bool     note_resting = false; | ||||
| 
 | ||||
| uint8_t current_note = 0; | ||||
| uint8_t rest_counter = 0; | ||||
| 
 | ||||
| #ifdef VIBRATO_ENABLE | ||||
| float vibrato_counter = 0; | ||||
| float vibrato_strength = .5; | ||||
| float vibrato_rate = 0.125; | ||||
| #endif | ||||
| 
 | ||||
| float polyphony_rate = 0; | ||||
| 
 | ||||
| static bool audio_initialized = false; | ||||
| 
 | ||||
| audio_config_t audio_config; | ||||
| 
 | ||||
| uint16_t envelope_index = 0; | ||||
| 
 | ||||
| void audio_init() { | ||||
| 
 | ||||
|     // Check EEPROM
 | ||||
|     if (!eeconfig_is_enabled()) | ||||
|     { | ||||
|         eeconfig_init(); | ||||
|     } | ||||
|     audio_config.raw = eeconfig_read_audio(); | ||||
| 
 | ||||
|     #ifdef PWM_AUDIO | ||||
| 
 | ||||
|         PLLFRQ = _BV(PDIV2); | ||||
|         PLLCSR = _BV(PLLE); | ||||
|         while(!(PLLCSR & _BV(PLOCK))); | ||||
|         PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */ | ||||
| 
 | ||||
|         /* Init a fast PWM on Timer4 */ | ||||
|         TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */ | ||||
|         TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */ | ||||
|         OCR4A = 0; | ||||
| 
 | ||||
|         /* Enable the OC4A output */ | ||||
|         DDRC |= _BV(PORTC6); | ||||
| 
 | ||||
|         DISABLE_AUDIO_COUNTER_3_ISR; // Turn off 3A interputs
 | ||||
| 
 | ||||
|         TCCR3A = 0x0; // Options not needed
 | ||||
|         TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC
 | ||||
|         OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback
 | ||||
| 
 | ||||
|     #else | ||||
| 
 | ||||
|     	// Set port PC6 (OC3A and /OC4A) as output
 | ||||
|         DDRC |= _BV(PORTC6); | ||||
| 
 | ||||
|         DISABLE_AUDIO_COUNTER_3_ISR; | ||||
| 
 | ||||
| 		// TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
 | ||||
| 		// Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
 | ||||
| 		// Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A)
 | ||||
| 		// Clock Select (CS3n) = 0b010 = Clock / 8
 | ||||
|         TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); | ||||
|         TCCR3B = (1 << WGM33)  | (1 << WGM32)  | (0 << CS32)  | (1 << CS31) | (0 << CS30); | ||||
| 
 | ||||
|     #endif | ||||
| 
 | ||||
|     audio_initialized = true; | ||||
| } | ||||
| 
 | ||||
| void stop_all_notes() { | ||||
|     if (!audio_initialized) { | ||||
|         audio_init(); | ||||
|     } | ||||
|     voices = 0; | ||||
|     #ifdef PWM_AUDIO | ||||
| 	    DISABLE_AUDIO_COUNTER_3_ISR; | ||||
|     #else | ||||
|         DISABLE_AUDIO_COUNTER_3_ISR; | ||||
|         DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||||
|     #endif | ||||
| 
 | ||||
|     playing_notes = false; | ||||
|     playing_note = false; | ||||
|     frequency = 0; | ||||
|     volume = 0; | ||||
| 
 | ||||
|     for (uint8_t i = 0; i < 8; i++) | ||||
|     { | ||||
|         frequencies[i] = 0; | ||||
|         volumes[i] = 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void stop_note(float freq) | ||||
| { | ||||
|     if (playing_note) { | ||||
|         if (!audio_initialized) { | ||||
|             audio_init(); | ||||
|         } | ||||
|         #ifdef PWM_AUDIO | ||||
|             freq = freq / SAMPLE_RATE; | ||||
|         #endif | ||||
|         for (int i = 7; i >= 0; i--) { | ||||
|             if (frequencies[i] == freq) { | ||||
|                 frequencies[i] = 0; | ||||
|                 volumes[i] = 0; | ||||
|                 for (int j = i; (j < 7); j++) { | ||||
|                     frequencies[j] = frequencies[j+1]; | ||||
|                     frequencies[j+1] = 0; | ||||
|                     volumes[j] = volumes[j+1]; | ||||
|                     volumes[j+1] = 0; | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         voices--; | ||||
|         if (voices < 0) | ||||
|             voices = 0; | ||||
|         if (voice_place >= voices) { | ||||
|             voice_place = 0; | ||||
|         } | ||||
|         if (voices == 0) { | ||||
|             #ifdef PWM_AUDIO | ||||
|                 DISABLE_AUDIO_COUNTER_3_ISR; | ||||
|             #else | ||||
|                 DISABLE_AUDIO_COUNTER_3_ISR; | ||||
|                 DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||||
|             #endif | ||||
|             frequency = 0; | ||||
|             volume = 0; | ||||
|             playing_note = false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #ifdef VIBRATO_ENABLE | ||||
| 
 | ||||
| float mod(float a, int b) | ||||
| { | ||||
|     float r = fmod(a, b); | ||||
|     return r < 0 ? r + b : r; | ||||
| } | ||||
| 
 | ||||
| float vibrato(float average_freq) { | ||||
|     #ifdef VIBRATO_STRENGTH_ENABLE | ||||
|         float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength); | ||||
|     #else | ||||
|         float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter]; | ||||
|     #endif | ||||
|     vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0/average_freq)), VIBRATO_LUT_LENGTH); | ||||
|     return vibrated_freq; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| ISR(TIMER3_COMPA_vect) | ||||
| { | ||||
|     if (playing_note) { | ||||
|         #ifdef PWM_AUDIO | ||||
|             if (voices == 1) { | ||||
|                 // SINE
 | ||||
|                 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2; | ||||
| 
 | ||||
|                 // SQUARE
 | ||||
|                 // if (((int)place) >= 1024){
 | ||||
|                 //     OCR4A = 0xFF >> 2;
 | ||||
|                 // } else {
 | ||||
|                 //     OCR4A = 0x00;
 | ||||
|                 // }
 | ||||
| 
 | ||||
|                 // SAWTOOTH
 | ||||
|                 // OCR4A = (int)place / 4;
 | ||||
| 
 | ||||
|                 // TRIANGLE
 | ||||
|                 // if (((int)place) >= 1024) {
 | ||||
|                 //     OCR4A = (int)place / 2;
 | ||||
|                 // } else {
 | ||||
|                 //     OCR4A = 2048 - (int)place / 2;
 | ||||
|                 // }
 | ||||
| 
 | ||||
|                 place += frequency; | ||||
| 
 | ||||
|                 if (place >= SINE_LENGTH) | ||||
|                     place -= SINE_LENGTH; | ||||
| 
 | ||||
|             } else { | ||||
|                 int sum = 0; | ||||
|                 for (int i = 0; i < voices; i++) { | ||||
|                     // SINE
 | ||||
|                     sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2; | ||||
| 
 | ||||
|                     // SQUARE
 | ||||
|                     // if (((int)places[i]) >= 1024){
 | ||||
|                     //     sum += 0xFF >> 2;
 | ||||
|                     // } else {
 | ||||
|                     //     sum += 0x00;
 | ||||
|                     // }
 | ||||
| 
 | ||||
|                     places[i] += frequencies[i]; | ||||
| 
 | ||||
|                     if (places[i] >= SINE_LENGTH) | ||||
|                         places[i] -= SINE_LENGTH; | ||||
|                 } | ||||
|                 OCR4A = sum; | ||||
|             } | ||||
|         #else | ||||
|             if (voices > 0) { | ||||
|                 float freq; | ||||
|                 if (polyphony_rate > 0) { | ||||
|                     if (voices > 1) { | ||||
|                         voice_place %= voices; | ||||
|                         if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { | ||||
|                             voice_place = (voice_place + 1) % voices; | ||||
|                             place = 0.0; | ||||
|                         } | ||||
|                     } | ||||
|                     #ifdef VIBRATO_ENABLE | ||||
|                     if (vibrato_strength > 0) { | ||||
|                         freq = vibrato(frequencies[voice_place]); | ||||
|                     } else { | ||||
|                     #else | ||||
|                     { | ||||
|                     #endif | ||||
|                         freq = frequencies[voice_place]; | ||||
|                     } | ||||
|                 } else { | ||||
|                     if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) { | ||||
|                         frequency = frequency * pow(2, 440/frequency/12/2); | ||||
|                     } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) { | ||||
|                         frequency = frequency * pow(2, -440/frequency/12/2); | ||||
|                     } else { | ||||
|                         frequency = frequencies[voices - 1]; | ||||
|                     } | ||||
| 
 | ||||
| 
 | ||||
|                     #ifdef VIBRATO_ENABLE | ||||
|                     if (vibrato_strength > 0) { | ||||
|                         freq = vibrato(frequency); | ||||
|                     } else { | ||||
|                     #else | ||||
|                     { | ||||
|                     #endif | ||||
|                         freq = frequency; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (envelope_index < 65535) { | ||||
|                     envelope_index++; | ||||
|                 } | ||||
|                 freq = voice_envelope(freq); | ||||
| 
 | ||||
|                 if (freq < 30.517578125) | ||||
|                     freq = 30.52; | ||||
|                 NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
 | ||||
|                 NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
 | ||||
|             } | ||||
|         #endif | ||||
|     } | ||||
| 
 | ||||
|     // SAMPLE
 | ||||
|     // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]);
 | ||||
| 
 | ||||
|     // place_int++;
 | ||||
| 
 | ||||
|     // if (place_int >= sample_length)
 | ||||
|     //     if (repeat)
 | ||||
|     //         place_int -= sample_length;
 | ||||
|     //     else
 | ||||
|     //         DISABLE_AUDIO_COUNTER_3_ISR;
 | ||||
| 
 | ||||
| 
 | ||||
|     if (playing_notes) { | ||||
|         #ifdef PWM_AUDIO | ||||
|             OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0; | ||||
| 
 | ||||
|             place += note_frequency; | ||||
|             if (place >= SINE_LENGTH) | ||||
|                 place -= SINE_LENGTH; | ||||
|         #else | ||||
|             if (note_frequency > 0) { | ||||
|                 float freq; | ||||
| 
 | ||||
|                 #ifdef VIBRATO_ENABLE | ||||
|                 if (vibrato_strength > 0) { | ||||
|                     freq = vibrato(note_frequency); | ||||
|                 } else { | ||||
|                 #else | ||||
|                 { | ||||
|                 #endif | ||||
|                     freq = note_frequency; | ||||
|                 } | ||||
| 
 | ||||
|                 if (envelope_index < 65535) { | ||||
|                     envelope_index++; | ||||
|                 } | ||||
|                 freq = voice_envelope(freq); | ||||
| 
 | ||||
|                 NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
 | ||||
|                 NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
 | ||||
|             } else { | ||||
|                 NOTE_PERIOD = 0; | ||||
|                 NOTE_DUTY_CYCLE = 0; | ||||
|             } | ||||
|         #endif | ||||
| 
 | ||||
| 
 | ||||
|         note_position++; | ||||
|         bool end_of_note = false; | ||||
|         if (NOTE_PERIOD > 0) | ||||
|             end_of_note = (note_position >= (note_length / NOTE_PERIOD * 0xFFFF)); | ||||
|         else | ||||
|             end_of_note = (note_position >= (note_length * 0x7FF)); | ||||
|         if (end_of_note) { | ||||
|             current_note++; | ||||
|             if (current_note >= notes_count) { | ||||
|                 if (notes_repeat) { | ||||
|                     current_note = 0; | ||||
|                 } else { | ||||
|                     #ifdef PWM_AUDIO | ||||
|                         DISABLE_AUDIO_COUNTER_3_ISR; | ||||
|                     #else | ||||
|                         DISABLE_AUDIO_COUNTER_3_ISR; | ||||
|                         DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||||
|                     #endif | ||||
|                     playing_notes = false; | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|             if (!note_resting && (notes_rest > 0)) { | ||||
|                 note_resting = true; | ||||
|                 note_frequency = 0; | ||||
|                 note_length = notes_rest; | ||||
|                 current_note--; | ||||
|             } else { | ||||
|                 note_resting = false; | ||||
|                 #ifdef PWM_AUDIO | ||||
|                     note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE; | ||||
|                     note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100); | ||||
|                 #else | ||||
|                     envelope_index = 0; | ||||
|                     note_frequency = (*notes_pointer)[current_note][0]; | ||||
|                     note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | ||||
|                 #endif | ||||
|             } | ||||
|             note_position = 0; | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     if (!audio_config.enable) { | ||||
|         playing_notes = false; | ||||
|         playing_note = false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void play_note(float freq, int vol) { | ||||
| 
 | ||||
|     if (!audio_initialized) { | ||||
|         audio_init(); | ||||
|     } | ||||
| 
 | ||||
| 	if (audio_config.enable && voices < 8) { | ||||
| 	    DISABLE_AUDIO_COUNTER_3_ISR; | ||||
| 
 | ||||
| 	    // Cancel notes if notes are playing
 | ||||
| 	    if (playing_notes) | ||||
| 	        stop_all_notes(); | ||||
| 
 | ||||
| 	    playing_note = true; | ||||
| 
 | ||||
| 	    envelope_index = 0; | ||||
| 
 | ||||
| 	    #ifdef PWM_AUDIO | ||||
| 	        freq = freq / SAMPLE_RATE; | ||||
| 	    #endif | ||||
| 	    if (freq > 0) { | ||||
| 	        frequencies[voices] = freq; | ||||
| 	        volumes[voices] = vol; | ||||
| 	        voices++; | ||||
| 	    } | ||||
| 
 | ||||
| 	    #ifdef PWM_AUDIO | ||||
| 	        ENABLE_AUDIO_COUNTER_3_ISR; | ||||
| 	    #else | ||||
| 	        ENABLE_AUDIO_COUNTER_3_ISR; | ||||
| 	        ENABLE_AUDIO_COUNTER_3_OUTPUT; | ||||
| 	    #endif | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) | ||||
| { | ||||
| 
 | ||||
|     if (!audio_initialized) { | ||||
|         audio_init(); | ||||
|     } | ||||
| 
 | ||||
| 	if (audio_config.enable) { | ||||
| 
 | ||||
| 	    DISABLE_AUDIO_COUNTER_3_ISR; | ||||
| 
 | ||||
| 		// Cancel note if a note is playing
 | ||||
| 	    if (playing_note) | ||||
| 	        stop_all_notes(); | ||||
| 
 | ||||
| 	    playing_notes = true; | ||||
| 
 | ||||
| 	    notes_pointer = np; | ||||
| 	    notes_count = n_count; | ||||
| 	    notes_repeat = n_repeat; | ||||
| 	    notes_rest = n_rest; | ||||
| 
 | ||||
| 	    place = 0; | ||||
| 	    current_note = 0; | ||||
| 
 | ||||
| 	    #ifdef PWM_AUDIO | ||||
| 	        note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE; | ||||
| 	        note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100); | ||||
| 	    #else | ||||
| 	        note_frequency = (*notes_pointer)[current_note][0]; | ||||
| 	        note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | ||||
| 	    #endif | ||||
| 	    note_position = 0; | ||||
| 
 | ||||
| 
 | ||||
| 	    #ifdef PWM_AUDIO | ||||
| 	        ENABLE_AUDIO_COUNTER_3_ISR; | ||||
| 	    #else | ||||
| 	        ENABLE_AUDIO_COUNTER_3_ISR; | ||||
| 	        ENABLE_AUDIO_COUNTER_3_OUTPUT; | ||||
| 	    #endif | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #ifdef PWM_AUDIO | ||||
| void play_sample(uint8_t * s, uint16_t l, bool r) { | ||||
|     if (!audio_initialized) { | ||||
|         audio_init(); | ||||
|     } | ||||
| 
 | ||||
|     if (audio_config.enable) { | ||||
|         DISABLE_AUDIO_COUNTER_3_ISR; | ||||
|         stop_all_notes(); | ||||
|         place_int = 0; | ||||
|         sample = s; | ||||
|         sample_length = l; | ||||
|         repeat = r; | ||||
| 
 | ||||
|         ENABLE_AUDIO_COUNTER_3_ISR; | ||||
|     } | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| void audio_toggle(void) { | ||||
|     audio_config.enable ^= 1; | ||||
|     eeconfig_update_audio(audio_config.raw); | ||||
| } | ||||
| 
 | ||||
| void audio_on(void) { | ||||
|     audio_config.enable = 1; | ||||
|     eeconfig_update_audio(audio_config.raw); | ||||
| } | ||||
| 
 | ||||
| void audio_off(void) { | ||||
|     audio_config.enable = 0; | ||||
|     eeconfig_update_audio(audio_config.raw); | ||||
| } | ||||
| 
 | ||||
| #ifdef VIBRATO_ENABLE | ||||
| 
 | ||||
| // Vibrato rate functions
 | ||||
| 
 | ||||
| void set_vibrato_rate(float rate) { | ||||
|     vibrato_rate = rate; | ||||
| } | ||||
| 
 | ||||
| void increase_vibrato_rate(float change) { | ||||
|     vibrato_rate *= change; | ||||
| } | ||||
| 
 | ||||
| void decrease_vibrato_rate(float change) { | ||||
|     vibrato_rate /= change; | ||||
| } | ||||
| 
 | ||||
| #ifdef VIBRATO_STRENGTH_ENABLE | ||||
| 
 | ||||
| void set_vibrato_strength(float strength) { | ||||
|     vibrato_strength = strength; | ||||
| } | ||||
| 
 | ||||
| void increase_vibrato_strength(float change) { | ||||
|     vibrato_strength *= change; | ||||
| } | ||||
| 
 | ||||
| void decrease_vibrato_strength(float change) { | ||||
|     vibrato_strength /= change; | ||||
| } | ||||
| 
 | ||||
| #endif  /* VIBRATO_STRENGTH_ENABLE */ | ||||
| 
 | ||||
| #endif /* VIBRATO_ENABLE */ | ||||
| 
 | ||||
| // Polyphony functions
 | ||||
| 
 | ||||
| void set_polyphony_rate(float rate) { | ||||
|     polyphony_rate = rate; | ||||
| } | ||||
| 
 | ||||
| void enable_polyphony() { | ||||
|     polyphony_rate = 5; | ||||
| } | ||||
| 
 | ||||
| void disable_polyphony() { | ||||
|     polyphony_rate = 0; | ||||
| } | ||||
| 
 | ||||
| void increase_polyphony_rate(float change) { | ||||
|     polyphony_rate *= change; | ||||
| } | ||||
| 
 | ||||
| void decrease_polyphony_rate(float change) { | ||||
|     polyphony_rate /= change; | ||||
| } | ||||
| 
 | ||||
| // Timbre function
 | ||||
| 
 | ||||
| void set_timbre(float timbre) { | ||||
|     note_timbre = timbre; | ||||
| } | ||||
| 
 | ||||
| // Tempo functions
 | ||||
| 
 | ||||
| void set_tempo(uint8_t tempo) { | ||||
|     note_tempo = tempo; | ||||
| } | ||||
| 
 | ||||
| void decrease_tempo(uint8_t tempo_change) { | ||||
|     note_tempo += tempo_change; | ||||
| } | ||||
| 
 | ||||
| void increase_tempo(uint8_t tempo_change) { | ||||
|     if (note_tempo - tempo_change < 10) { | ||||
|         note_tempo = 10; | ||||
|     } else { | ||||
|         note_tempo -= tempo_change; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //------------------------------------------------------------------------------
 | ||||
| // Override these functions in your keymap file to play different tunes on
 | ||||
| // startup and bootloader jump
 | ||||
| __attribute__ ((weak)) | ||||
| void play_startup_tone() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| __attribute__ ((weak)) | ||||
| void play_goodbye_tone() | ||||
| { | ||||
| } | ||||
| //------------------------------------------------------------------------------
 | ||||
| @ -1,357 +0,0 @@ | ||||
| #include <avr/io.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include <avr/pgmspace.h> | ||||
| 
 | ||||
| #define FREQUENCY_LUT_LENGTH 349 | ||||
| 
 | ||||
| const uint16_t FREQUENCY_LUT[FREQUENCY_LUT_LENGTH] = { | ||||
| 0x8E0B, | ||||
| 0x8C02, | ||||
| 0x8A00, | ||||
| 0x8805, | ||||
| 0x8612, | ||||
| 0x8426, | ||||
| 0x8241, | ||||
| 0x8063, | ||||
| 0x7E8C, | ||||
| 0x7CBB, | ||||
| 0x7AF2, | ||||
| 0x792E, | ||||
| 0x7772, | ||||
| 0x75BB, | ||||
| 0x740B, | ||||
| 0x7261, | ||||
| 0x70BD, | ||||
| 0x6F20, | ||||
| 0x6D88, | ||||
| 0x6BF6, | ||||
| 0x6A69, | ||||
| 0x68E3, | ||||
| 0x6762, | ||||
| 0x65E6, | ||||
| 0x6470, | ||||
| 0x6300, | ||||
| 0x6194, | ||||
| 0x602E, | ||||
| 0x5ECD, | ||||
| 0x5D71, | ||||
| 0x5C1A, | ||||
| 0x5AC8, | ||||
| 0x597B, | ||||
| 0x5833, | ||||
| 0x56EF, | ||||
| 0x55B0, | ||||
| 0x5475, | ||||
| 0x533F, | ||||
| 0x520E, | ||||
| 0x50E1, | ||||
| 0x4FB8, | ||||
| 0x4E93, | ||||
| 0x4D73, | ||||
| 0x4C57, | ||||
| 0x4B3E, | ||||
| 0x4A2A, | ||||
| 0x491A, | ||||
| 0x480E, | ||||
| 0x4705, | ||||
| 0x4601, | ||||
| 0x4500, | ||||
| 0x4402, | ||||
| 0x4309, | ||||
| 0x4213, | ||||
| 0x4120, | ||||
| 0x4031, | ||||
| 0x3F46, | ||||
| 0x3E5D, | ||||
| 0x3D79, | ||||
| 0x3C97, | ||||
| 0x3BB9, | ||||
| 0x3ADD, | ||||
| 0x3A05, | ||||
| 0x3930, | ||||
| 0x385E, | ||||
| 0x3790, | ||||
| 0x36C4, | ||||
| 0x35FB, | ||||
| 0x3534, | ||||
| 0x3471, | ||||
| 0x33B1, | ||||
| 0x32F3, | ||||
| 0x3238, | ||||
| 0x3180, | ||||
| 0x30CA, | ||||
| 0x3017, | ||||
| 0x2F66, | ||||
| 0x2EB8, | ||||
| 0x2E0D, | ||||
| 0x2D64, | ||||
| 0x2CBD, | ||||
| 0x2C19, | ||||
| 0x2B77, | ||||
| 0x2AD8, | ||||
| 0x2A3A, | ||||
| 0x299F, | ||||
| 0x2907, | ||||
| 0x2870, | ||||
| 0x27DC, | ||||
| 0x2749, | ||||
| 0x26B9, | ||||
| 0x262B, | ||||
| 0x259F, | ||||
| 0x2515, | ||||
| 0x248D, | ||||
| 0x2407, | ||||
| 0x2382, | ||||
| 0x2300, | ||||
| 0x2280, | ||||
| 0x2201, | ||||
| 0x2184, | ||||
| 0x2109, | ||||
| 0x2090, | ||||
| 0x2018, | ||||
| 0x1FA3, | ||||
| 0x1F2E, | ||||
| 0x1EBC, | ||||
| 0x1E4B, | ||||
| 0x1DDC, | ||||
| 0x1D6E, | ||||
| 0x1D02, | ||||
| 0x1C98, | ||||
| 0x1C2F, | ||||
| 0x1BC8, | ||||
| 0x1B62, | ||||
| 0x1AFD, | ||||
| 0x1A9A, | ||||
| 0x1A38, | ||||
| 0x19D8, | ||||
| 0x1979, | ||||
| 0x191C, | ||||
| 0x18C0, | ||||
| 0x1865, | ||||
| 0x180B, | ||||
| 0x17B3, | ||||
| 0x175C, | ||||
| 0x1706, | ||||
| 0x16B2, | ||||
| 0x165E, | ||||
| 0x160C, | ||||
| 0x15BB, | ||||
| 0x156C, | ||||
| 0x151D, | ||||
| 0x14CF, | ||||
| 0x1483, | ||||
| 0x1438, | ||||
| 0x13EE, | ||||
| 0x13A4, | ||||
| 0x135C, | ||||
| 0x1315, | ||||
| 0x12CF, | ||||
| 0x128A, | ||||
| 0x1246, | ||||
| 0x1203, | ||||
| 0x11C1, | ||||
| 0x1180, | ||||
| 0x1140, | ||||
| 0x1100, | ||||
| 0x10C2, | ||||
| 0x1084, | ||||
| 0x1048, | ||||
| 0x100C, | ||||
| 0xFD1, | ||||
| 0xF97, | ||||
| 0xF5E, | ||||
| 0xF25, | ||||
| 0xEEE, | ||||
| 0xEB7, | ||||
| 0xE81, | ||||
| 0xE4C, | ||||
| 0xE17, | ||||
| 0xDE4, | ||||
| 0xDB1, | ||||
| 0xD7E, | ||||
| 0xD4D, | ||||
| 0xD1C, | ||||
| 0xCEC, | ||||
| 0xCBC, | ||||
| 0xC8E, | ||||
| 0xC60, | ||||
| 0xC32, | ||||
| 0xC05, | ||||
| 0xBD9, | ||||
| 0xBAE, | ||||
| 0xB83, | ||||
| 0xB59, | ||||
| 0xB2F, | ||||
| 0xB06, | ||||
| 0xADD, | ||||
| 0xAB6, | ||||
| 0xA8E, | ||||
| 0xA67, | ||||
| 0xA41, | ||||
| 0xA1C, | ||||
| 0x9F7, | ||||
| 0x9D2, | ||||
| 0x9AE, | ||||
| 0x98A, | ||||
| 0x967, | ||||
| 0x945, | ||||
| 0x923, | ||||
| 0x901, | ||||
| 0x8E0, | ||||
| 0x8C0, | ||||
| 0x8A0, | ||||
| 0x880, | ||||
| 0x861, | ||||
| 0x842, | ||||
| 0x824, | ||||
| 0x806, | ||||
| 0x7E8, | ||||
| 0x7CB, | ||||
| 0x7AF, | ||||
| 0x792, | ||||
| 0x777, | ||||
| 0x75B, | ||||
| 0x740, | ||||
| 0x726, | ||||
| 0x70B, | ||||
| 0x6F2, | ||||
| 0x6D8, | ||||
| 0x6BF, | ||||
| 0x6A6, | ||||
| 0x68E, | ||||
| 0x676, | ||||
| 0x65E, | ||||
| 0x647, | ||||
| 0x630, | ||||
| 0x619, | ||||
| 0x602, | ||||
| 0x5EC, | ||||
| 0x5D7, | ||||
| 0x5C1, | ||||
| 0x5AC, | ||||
| 0x597, | ||||
| 0x583, | ||||
| 0x56E, | ||||
| 0x55B, | ||||
| 0x547, | ||||
| 0x533, | ||||
| 0x520, | ||||
| 0x50E, | ||||
| 0x4FB, | ||||
| 0x4E9, | ||||
| 0x4D7, | ||||
| 0x4C5, | ||||
| 0x4B3, | ||||
| 0x4A2, | ||||
| 0x491, | ||||
| 0x480, | ||||
| 0x470, | ||||
| 0x460, | ||||
| 0x450, | ||||
| 0x440, | ||||
| 0x430, | ||||
| 0x421, | ||||
| 0x412, | ||||
| 0x403, | ||||
| 0x3F4, | ||||
| 0x3E5, | ||||
| 0x3D7, | ||||
| 0x3C9, | ||||
| 0x3BB, | ||||
| 0x3AD, | ||||
| 0x3A0, | ||||
| 0x393, | ||||
| 0x385, | ||||
| 0x379, | ||||
| 0x36C, | ||||
| 0x35F, | ||||
| 0x353, | ||||
| 0x347, | ||||
| 0x33B, | ||||
| 0x32F, | ||||
| 0x323, | ||||
| 0x318, | ||||
| 0x30C, | ||||
| 0x301, | ||||
| 0x2F6, | ||||
| 0x2EB, | ||||
| 0x2E0, | ||||
| 0x2D6, | ||||
| 0x2CB, | ||||
| 0x2C1, | ||||
| 0x2B7, | ||||
| 0x2AD, | ||||
| 0x2A3, | ||||
| 0x299, | ||||
| 0x290, | ||||
| 0x287, | ||||
| 0x27D, | ||||
| 0x274, | ||||
| 0x26B, | ||||
| 0x262, | ||||
| 0x259, | ||||
| 0x251, | ||||
| 0x248, | ||||
| 0x240, | ||||
| 0x238, | ||||
| 0x230, | ||||
| 0x228, | ||||
| 0x220, | ||||
| 0x218, | ||||
| 0x210, | ||||
| 0x209, | ||||
| 0x201, | ||||
| 0x1FA, | ||||
| 0x1F2, | ||||
| 0x1EB, | ||||
| 0x1E4, | ||||
| 0x1DD, | ||||
| 0x1D6, | ||||
| 0x1D0, | ||||
| 0x1C9, | ||||
| 0x1C2, | ||||
| 0x1BC, | ||||
| 0x1B6, | ||||
| 0x1AF, | ||||
| 0x1A9, | ||||
| 0x1A3, | ||||
| 0x19D, | ||||
| 0x197, | ||||
| 0x191, | ||||
| 0x18C, | ||||
| 0x186, | ||||
| 0x180, | ||||
| 0x17B, | ||||
| 0x175, | ||||
| 0x170, | ||||
| 0x16B, | ||||
| 0x165, | ||||
| 0x160, | ||||
| 0x15B, | ||||
| 0x156, | ||||
| 0x151, | ||||
| 0x14C, | ||||
| 0x148, | ||||
| 0x143, | ||||
| 0x13E, | ||||
| 0x13A, | ||||
| 0x135, | ||||
| 0x131, | ||||
| 0x12C, | ||||
| 0x128, | ||||
| 0x124, | ||||
| 0x120, | ||||
| 0x11C, | ||||
| 0x118, | ||||
| 0x114, | ||||
| 0x110, | ||||
| 0x10C, | ||||
| 0x108, | ||||
| 0x104, | ||||
| 0x100, | ||||
| 0xFD, | ||||
| 0xF9, | ||||
| 0xF5, | ||||
| 0xF2, | ||||
| 0xEE | ||||
| }; | ||||
							
								
								
									
										382
									
								
								quantum/audio/luts.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										382
									
								
								quantum/audio/luts.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,382 @@ | ||||
| #include <avr/io.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include <avr/pgmspace.h> | ||||
| #include "luts.h" | ||||
| 
 | ||||
| const float vibrato_lut[VIBRATO_LUT_LENGTH] = | ||||
| { | ||||
| 	1.0022336811487, | ||||
| 	1.0042529943610, | ||||
| 	1.0058584256028, | ||||
| 	1.0068905285205, | ||||
| 	1.0072464122237, | ||||
| 	1.0068905285205, | ||||
| 	1.0058584256028, | ||||
| 	1.0042529943610, | ||||
| 	1.0022336811487, | ||||
| 	1.0000000000000, | ||||
| 	0.9977712970630, | ||||
| 	0.9957650169978, | ||||
| 	0.9941756956510, | ||||
| 	0.9931566259436, | ||||
| 	0.9928057204913, | ||||
| 	0.9931566259436, | ||||
| 	0.9941756956510, | ||||
| 	0.9957650169978, | ||||
| 	0.9977712970630, | ||||
| 	1.0000000000000, | ||||
| }; | ||||
| 
 | ||||
| const uint16_t frequency_lut[FREQUENCY_LUT_LENGTH] = | ||||
| { | ||||
| 	0x8E0B, | ||||
| 	0x8C02, | ||||
| 	0x8A00, | ||||
| 	0x8805, | ||||
| 	0x8612, | ||||
| 	0x8426, | ||||
| 	0x8241, | ||||
| 	0x8063, | ||||
| 	0x7E8C, | ||||
| 	0x7CBB, | ||||
| 	0x7AF2, | ||||
| 	0x792E, | ||||
| 	0x7772, | ||||
| 	0x75BB, | ||||
| 	0x740B, | ||||
| 	0x7261, | ||||
| 	0x70BD, | ||||
| 	0x6F20, | ||||
| 	0x6D88, | ||||
| 	0x6BF6, | ||||
| 	0x6A69, | ||||
| 	0x68E3, | ||||
| 	0x6762, | ||||
| 	0x65E6, | ||||
| 	0x6470, | ||||
| 	0x6300, | ||||
| 	0x6194, | ||||
| 	0x602E, | ||||
| 	0x5ECD, | ||||
| 	0x5D71, | ||||
| 	0x5C1A, | ||||
| 	0x5AC8, | ||||
| 	0x597B, | ||||
| 	0x5833, | ||||
| 	0x56EF, | ||||
| 	0x55B0, | ||||
| 	0x5475, | ||||
| 	0x533F, | ||||
| 	0x520E, | ||||
| 	0x50E1, | ||||
| 	0x4FB8, | ||||
| 	0x4E93, | ||||
| 	0x4D73, | ||||
| 	0x4C57, | ||||
| 	0x4B3E, | ||||
| 	0x4A2A, | ||||
| 	0x491A, | ||||
| 	0x480E, | ||||
| 	0x4705, | ||||
| 	0x4601, | ||||
| 	0x4500, | ||||
| 	0x4402, | ||||
| 	0x4309, | ||||
| 	0x4213, | ||||
| 	0x4120, | ||||
| 	0x4031, | ||||
| 	0x3F46, | ||||
| 	0x3E5D, | ||||
| 	0x3D79, | ||||
| 	0x3C97, | ||||
| 	0x3BB9, | ||||
| 	0x3ADD, | ||||
| 	0x3A05, | ||||
| 	0x3930, | ||||
| 	0x385E, | ||||
| 	0x3790, | ||||
| 	0x36C4, | ||||
| 	0x35FB, | ||||
| 	0x3534, | ||||
| 	0x3471, | ||||
| 	0x33B1, | ||||
| 	0x32F3, | ||||
| 	0x3238, | ||||
| 	0x3180, | ||||
| 	0x30CA, | ||||
| 	0x3017, | ||||
| 	0x2F66, | ||||
| 	0x2EB8, | ||||
| 	0x2E0D, | ||||
| 	0x2D64, | ||||
| 	0x2CBD, | ||||
| 	0x2C19, | ||||
| 	0x2B77, | ||||
| 	0x2AD8, | ||||
| 	0x2A3A, | ||||
| 	0x299F, | ||||
| 	0x2907, | ||||
| 	0x2870, | ||||
| 	0x27DC, | ||||
| 	0x2749, | ||||
| 	0x26B9, | ||||
| 	0x262B, | ||||
| 	0x259F, | ||||
| 	0x2515, | ||||
| 	0x248D, | ||||
| 	0x2407, | ||||
| 	0x2382, | ||||
| 	0x2300, | ||||
| 	0x2280, | ||||
| 	0x2201, | ||||
| 	0x2184, | ||||
| 	0x2109, | ||||
| 	0x2090, | ||||
| 	0x2018, | ||||
| 	0x1FA3, | ||||
| 	0x1F2E, | ||||
| 	0x1EBC, | ||||
| 	0x1E4B, | ||||
| 	0x1DDC, | ||||
| 	0x1D6E, | ||||
| 	0x1D02, | ||||
| 	0x1C98, | ||||
| 	0x1C2F, | ||||
| 	0x1BC8, | ||||
| 	0x1B62, | ||||
| 	0x1AFD, | ||||
| 	0x1A9A, | ||||
| 	0x1A38, | ||||
| 	0x19D8, | ||||
| 	0x1979, | ||||
| 	0x191C, | ||||
| 	0x18C0, | ||||
| 	0x1865, | ||||
| 	0x180B, | ||||
| 	0x17B3, | ||||
| 	0x175C, | ||||
| 	0x1706, | ||||
| 	0x16B2, | ||||
| 	0x165E, | ||||
| 	0x160C, | ||||
| 	0x15BB, | ||||
| 	0x156C, | ||||
| 	0x151D, | ||||
| 	0x14CF, | ||||
| 	0x1483, | ||||
| 	0x1438, | ||||
| 	0x13EE, | ||||
| 	0x13A4, | ||||
| 	0x135C, | ||||
| 	0x1315, | ||||
| 	0x12CF, | ||||
| 	0x128A, | ||||
| 	0x1246, | ||||
| 	0x1203, | ||||
| 	0x11C1, | ||||
| 	0x1180, | ||||
| 	0x1140, | ||||
| 	0x1100, | ||||
| 	0x10C2, | ||||
| 	0x1084, | ||||
| 	0x1048, | ||||
| 	0x100C, | ||||
| 	0xFD1, | ||||
| 	0xF97, | ||||
| 	0xF5E, | ||||
| 	0xF25, | ||||
| 	0xEEE, | ||||
| 	0xEB7, | ||||
| 	0xE81, | ||||
| 	0xE4C, | ||||
| 	0xE17, | ||||
| 	0xDE4, | ||||
| 	0xDB1, | ||||
| 	0xD7E, | ||||
| 	0xD4D, | ||||
| 	0xD1C, | ||||
| 	0xCEC, | ||||
| 	0xCBC, | ||||
| 	0xC8E, | ||||
| 	0xC60, | ||||
| 	0xC32, | ||||
| 	0xC05, | ||||
| 	0xBD9, | ||||
| 	0xBAE, | ||||
| 	0xB83, | ||||
| 	0xB59, | ||||
| 	0xB2F, | ||||
| 	0xB06, | ||||
| 	0xADD, | ||||
| 	0xAB6, | ||||
| 	0xA8E, | ||||
| 	0xA67, | ||||
| 	0xA41, | ||||
| 	0xA1C, | ||||
| 	0x9F7, | ||||
| 	0x9D2, | ||||
| 	0x9AE, | ||||
| 	0x98A, | ||||
| 	0x967, | ||||
| 	0x945, | ||||
| 	0x923, | ||||
| 	0x901, | ||||
| 	0x8E0, | ||||
| 	0x8C0, | ||||
| 	0x8A0, | ||||
| 	0x880, | ||||
| 	0x861, | ||||
| 	0x842, | ||||
| 	0x824, | ||||
| 	0x806, | ||||
| 	0x7E8, | ||||
| 	0x7CB, | ||||
| 	0x7AF, | ||||
| 	0x792, | ||||
| 	0x777, | ||||
| 	0x75B, | ||||
| 	0x740, | ||||
| 	0x726, | ||||
| 	0x70B, | ||||
| 	0x6F2, | ||||
| 	0x6D8, | ||||
| 	0x6BF, | ||||
| 	0x6A6, | ||||
| 	0x68E, | ||||
| 	0x676, | ||||
| 	0x65E, | ||||
| 	0x647, | ||||
| 	0x630, | ||||
| 	0x619, | ||||
| 	0x602, | ||||
| 	0x5EC, | ||||
| 	0x5D7, | ||||
| 	0x5C1, | ||||
| 	0x5AC, | ||||
| 	0x597, | ||||
| 	0x583, | ||||
| 	0x56E, | ||||
| 	0x55B, | ||||
| 	0x547, | ||||
| 	0x533, | ||||
| 	0x520, | ||||
| 	0x50E, | ||||
| 	0x4FB, | ||||
| 	0x4E9, | ||||
| 	0x4D7, | ||||
| 	0x4C5, | ||||
| 	0x4B3, | ||||
| 	0x4A2, | ||||
| 	0x491, | ||||
| 	0x480, | ||||
| 	0x470, | ||||
| 	0x460, | ||||
| 	0x450, | ||||
| 	0x440, | ||||
| 	0x430, | ||||
| 	0x421, | ||||
| 	0x412, | ||||
| 	0x403, | ||||
| 	0x3F4, | ||||
| 	0x3E5, | ||||
| 	0x3D7, | ||||
| 	0x3C9, | ||||
| 	0x3BB, | ||||
| 	0x3AD, | ||||
| 	0x3A0, | ||||
| 	0x393, | ||||
| 	0x385, | ||||
| 	0x379, | ||||
| 	0x36C, | ||||
| 	0x35F, | ||||
| 	0x353, | ||||
| 	0x347, | ||||
| 	0x33B, | ||||
| 	0x32F, | ||||
| 	0x323, | ||||
| 	0x318, | ||||
| 	0x30C, | ||||
| 	0x301, | ||||
| 	0x2F6, | ||||
| 	0x2EB, | ||||
| 	0x2E0, | ||||
| 	0x2D6, | ||||
| 	0x2CB, | ||||
| 	0x2C1, | ||||
| 	0x2B7, | ||||
| 	0x2AD, | ||||
| 	0x2A3, | ||||
| 	0x299, | ||||
| 	0x290, | ||||
| 	0x287, | ||||
| 	0x27D, | ||||
| 	0x274, | ||||
| 	0x26B, | ||||
| 	0x262, | ||||
| 	0x259, | ||||
| 	0x251, | ||||
| 	0x248, | ||||
| 	0x240, | ||||
| 	0x238, | ||||
| 	0x230, | ||||
| 	0x228, | ||||
| 	0x220, | ||||
| 	0x218, | ||||
| 	0x210, | ||||
| 	0x209, | ||||
| 	0x201, | ||||
| 	0x1FA, | ||||
| 	0x1F2, | ||||
| 	0x1EB, | ||||
| 	0x1E4, | ||||
| 	0x1DD, | ||||
| 	0x1D6, | ||||
| 	0x1D0, | ||||
| 	0x1C9, | ||||
| 	0x1C2, | ||||
| 	0x1BC, | ||||
| 	0x1B6, | ||||
| 	0x1AF, | ||||
| 	0x1A9, | ||||
| 	0x1A3, | ||||
| 	0x19D, | ||||
| 	0x197, | ||||
| 	0x191, | ||||
| 	0x18C, | ||||
| 	0x186, | ||||
| 	0x180, | ||||
| 	0x17B, | ||||
| 	0x175, | ||||
| 	0x170, | ||||
| 	0x16B, | ||||
| 	0x165, | ||||
| 	0x160, | ||||
| 	0x15B, | ||||
| 	0x156, | ||||
| 	0x151, | ||||
| 	0x14C, | ||||
| 	0x148, | ||||
| 	0x143, | ||||
| 	0x13E, | ||||
| 	0x13A, | ||||
| 	0x135, | ||||
| 	0x131, | ||||
| 	0x12C, | ||||
| 	0x128, | ||||
| 	0x124, | ||||
| 	0x120, | ||||
| 	0x11C, | ||||
| 	0x118, | ||||
| 	0x114, | ||||
| 	0x110, | ||||
| 	0x10C, | ||||
| 	0x108, | ||||
| 	0x104, | ||||
| 	0x100, | ||||
| 	0xFD, | ||||
| 	0xF9, | ||||
| 	0xF5, | ||||
| 	0xF2, | ||||
| 	0xEE, | ||||
| }; | ||||
| 
 | ||||
							
								
								
									
										15
									
								
								quantum/audio/luts.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								quantum/audio/luts.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| #include <avr/io.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include <avr/pgmspace.h> | ||||
| 
 | ||||
| #ifndef LUTS_H | ||||
| #define LUTS_H | ||||
| 
 | ||||
| #define VIBRATO_LUT_LENGTH 20 | ||||
| 
 | ||||
| #define FREQUENCY_LUT_LENGTH 349 | ||||
| 
 | ||||
| extern const float vibrato_lut[VIBRATO_LUT_LENGTH]; | ||||
| extern const uint16_t frequency_lut[FREQUENCY_LUT_LENGTH]; | ||||
| 
 | ||||
| #endif /* LUTS_H */ | ||||
| @ -1,28 +0,0 @@ | ||||
| #include <avr/io.h> | ||||
| #include <avr/interrupt.h> | ||||
| #include <avr/pgmspace.h> | ||||
| 
 | ||||
| #define VIBRATO_LUT_LENGTH 20 | ||||
| 
 | ||||
| const float VIBRATO_LUT[VIBRATO_LUT_LENGTH] = { \ | ||||
| 1.00223368114872, | ||||
| 1.00425299436105, | ||||
| 1.00585842560279, | ||||
| 1.00689052852052, | ||||
| 1.0072464122237, | ||||
| 1.00689052852052, | ||||
| 1.00585842560279, | ||||
| 1.00425299436105, | ||||
| 1.00223368114872, | ||||
| 1, | ||||
| 0.99777129706302, | ||||
| 0.99576501699778, | ||||
| 0.994175695650927, | ||||
| 0.993156625943589, | ||||
| 0.992805720491269, | ||||
| 0.993156625943589, | ||||
| 0.994175695650927, | ||||
| 0.99576501699778, | ||||
| 0.99777129706302, | ||||
| 1 | ||||
| }; | ||||
| @ -1,6 +1,6 @@ | ||||
| #include "voices.h" | ||||
| #include "audio.h" | ||||
| #include "stdlib.h" | ||||
| #include "vibrato_lut.h" | ||||
| 
 | ||||
| // these are imported from audio.c
 | ||||
| extern uint16_t envelope_index; | ||||
| @ -109,7 +109,7 @@ float voice_envelope(float frequency) { | ||||
|                 case 0 ... VOICE_VIBRATO_DELAY: | ||||
|                     break; | ||||
|                 default: | ||||
|                     frequency = frequency * VIBRATO_LUT[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1))/1000*VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)]; | ||||
|                     frequency = frequency * vibrato_lut[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1))/1000*VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)]; | ||||
|                     break; | ||||
|             } | ||||
|             break; | ||||
| @ -161,3 +161,5 @@ float voice_envelope(float frequency) { | ||||
| 
 | ||||
|     return frequency; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -2,8 +2,7 @@ | ||||
| #include <stdbool.h> | ||||
| #include <avr/io.h> | ||||
| #include <util/delay.h> | ||||
| #include "musical_notes.h" | ||||
| #include "song_list.h" | ||||
| #include "luts.h" | ||||
| 
 | ||||
| #ifndef VOICES_H | ||||
| #define VOICES_H | ||||
|  | ||||
| @ -24,10 +24,14 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
| #include "action_macro.h" | ||||
| #include "debug.h" | ||||
| #include "backlight.h" | ||||
| #include "keymap_midi.h" | ||||
| #include "bootloader.h" | ||||
| #include "eeconfig.h" | ||||
| 
 | ||||
| #ifdef MIDI_ENABLE | ||||
| 	#include "keymap_midi.h" | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| extern keymap_config_t keymap_config; | ||||
| 
 | ||||
| #include <stdio.h> | ||||
|  | ||||
| @ -29,6 +29,7 @@ endif | ||||
| 
 | ||||
| ifeq ($(strip $(AUDIO_ENABLE)), yes) | ||||
| 	SRC += $(QUANTUM_DIR)/audio/audio.c $(QUANTUM_DIR)/audio/voices.c | ||||
| 	SRC += $(QUANTUM_DIR)/audio/audio.c $(QUANTUM_DIR)/audio/luts.c | ||||
| endif | ||||
| 
 | ||||
| ifeq ($(strip $(UNICODE_ENABLE)), yes) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 IBNobody
						IBNobody