diff options
Diffstat (limited to 'quantum/audio/audio.c')
| -rw-r--r-- | quantum/audio/audio.c | 334 |
1 files changed, 180 insertions, 154 deletions
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c index ead5fbf3e..597073611 100644 --- a/quantum/audio/audio.c +++ b/quantum/audio/audio.c | |||
| @@ -1,3 +1,18 @@ | |||
| 1 | /* Copyright 2016 Jack Humbert | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 1 | #include <stdio.h> | 16 | #include <stdio.h> |
| 2 | #include <string.h> | 17 | #include <string.h> |
| 3 | //#include <math.h> | 18 | //#include <math.h> |
| @@ -77,6 +92,7 @@ static bool audio_initialized = false; | |||
| 77 | audio_config_t audio_config; | 92 | audio_config_t audio_config; |
| 78 | 93 | ||
| 79 | uint16_t envelope_index = 0; | 94 | uint16_t envelope_index = 0; |
| 95 | bool glissando = true; | ||
| 80 | 96 | ||
| 81 | void audio_init() | 97 | void audio_init() |
| 82 | { | 98 | { |
| @@ -88,15 +104,15 @@ void audio_init() | |||
| 88 | } | 104 | } |
| 89 | audio_config.raw = eeconfig_read_audio(); | 105 | audio_config.raw = eeconfig_read_audio(); |
| 90 | 106 | ||
| 91 | // Set port PC6 (OC3A and /OC4A) as output | 107 | // Set port PC6 (OC3A and /OC4A) as output |
| 92 | DDRC |= _BV(PORTC6); | 108 | DDRC |= _BV(PORTC6); |
| 93 | 109 | ||
| 94 | DISABLE_AUDIO_COUNTER_3_ISR; | 110 | DISABLE_AUDIO_COUNTER_3_ISR; |
| 95 | 111 | ||
| 96 | // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers | 112 | // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers |
| 97 | // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 | 113 | // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 |
| 98 | // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A) | 114 | // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A) |
| 99 | // Clock Select (CS3n) = 0b010 = Clock / 8 | 115 | // Clock Select (CS3n) = 0b010 = Clock / 8 |
| 100 | TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); | 116 | TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); |
| 101 | TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); | 117 | TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); |
| 102 | 118 | ||
| @@ -105,6 +121,8 @@ void audio_init() | |||
| 105 | 121 | ||
| 106 | void stop_all_notes() | 122 | void stop_all_notes() |
| 107 | { | 123 | { |
| 124 | dprintf("audio stop all notes"); | ||
| 125 | |||
| 108 | if (!audio_initialized) { | 126 | if (!audio_initialized) { |
| 109 | audio_init(); | 127 | audio_init(); |
| 110 | } | 128 | } |
| @@ -127,6 +145,8 @@ void stop_all_notes() | |||
| 127 | 145 | ||
| 128 | void stop_note(float freq) | 146 | void stop_note(float freq) |
| 129 | { | 147 | { |
| 148 | dprintf("audio stop note freq=%d", (int)freq); | ||
| 149 | |||
| 130 | if (playing_note) { | 150 | if (playing_note) { |
| 131 | if (!audio_initialized) { | 151 | if (!audio_initialized) { |
| 132 | audio_init(); | 152 | audio_init(); |
| @@ -182,155 +202,161 @@ float vibrato(float average_freq) { | |||
| 182 | 202 | ||
| 183 | ISR(TIMER3_COMPA_vect) | 203 | ISR(TIMER3_COMPA_vect) |
| 184 | { | 204 | { |
| 185 | float freq; | 205 | float freq; |
| 186 | 206 | ||
| 187 | if (playing_note) { | 207 | if (playing_note) { |
| 188 | if (voices > 0) { | 208 | if (voices > 0) { |
| 189 | if (polyphony_rate > 0) { | 209 | if (polyphony_rate > 0) { |
| 190 | if (voices > 1) { | 210 | if (voices > 1) { |
| 191 | voice_place %= voices; | 211 | voice_place %= voices; |
| 192 | if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { | 212 | if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { |
| 193 | voice_place = (voice_place + 1) % voices; | 213 | voice_place = (voice_place + 1) % voices; |
| 194 | place = 0.0; | 214 | place = 0.0; |
| 195 | } | 215 | } |
| 196 | } | 216 | } |
| 197 | 217 | ||
| 198 | #ifdef VIBRATO_ENABLE | 218 | #ifdef VIBRATO_ENABLE |
| 199 | if (vibrato_strength > 0) { | 219 | if (vibrato_strength > 0) { |
| 200 | freq = vibrato(frequencies[voice_place]); | 220 | freq = vibrato(frequencies[voice_place]); |
| 201 | } else { | 221 | } else { |
| 202 | freq = frequencies[voice_place]; | 222 | freq = frequencies[voice_place]; |
| 203 | } | 223 | } |
| 204 | #else | 224 | #else |
| 205 | freq = frequencies[voice_place]; | 225 | freq = frequencies[voice_place]; |
| 206 | #endif | 226 | #endif |
| 207 | } else { | 227 | } else { |
| 208 | if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) { | 228 | if (glissando) { |
| 209 | frequency = frequency * pow(2, 440/frequency/12/2); | 229 | if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) { |
| 210 | } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) { | 230 | frequency = frequency * pow(2, 440/frequency/12/2); |
| 211 | frequency = frequency * pow(2, -440/frequency/12/2); | 231 | } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) { |
| 212 | } else { | 232 | frequency = frequency * pow(2, -440/frequency/12/2); |
| 213 | frequency = frequencies[voices - 1]; | 233 | } else { |
| 214 | } | 234 | frequency = frequencies[voices - 1]; |
| 215 | 235 | } | |
| 216 | #ifdef VIBRATO_ENABLE | 236 | } else { |
| 217 | if (vibrato_strength > 0) { | 237 | frequency = frequencies[voices - 1]; |
| 218 | freq = vibrato(frequency); | 238 | } |
| 219 | } else { | 239 | |
| 220 | freq = frequency; | 240 | #ifdef VIBRATO_ENABLE |
| 221 | } | 241 | if (vibrato_strength > 0) { |
| 222 | #else | 242 | freq = vibrato(frequency); |
| 223 | freq = frequency; | 243 | } else { |
| 224 | #endif | 244 | freq = frequency; |
| 225 | } | 245 | } |
| 226 | 246 | #else | |
| 227 | if (envelope_index < 65535) { | 247 | freq = frequency; |
| 228 | envelope_index++; | 248 | #endif |
| 229 | } | 249 | } |
| 230 | 250 | ||
| 231 | freq = voice_envelope(freq); | 251 | if (envelope_index < 65535) { |
| 232 | 252 | envelope_index++; | |
| 233 | if (freq < 30.517578125) { | 253 | } |
| 234 | freq = 30.52; | 254 | |
| 235 | } | 255 | freq = voice_envelope(freq); |
| 236 | 256 | ||
| 237 | TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | 257 | if (freq < 30.517578125) { |
| 238 | TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); | 258 | freq = 30.52; |
| 239 | } | 259 | } |
| 240 | } | 260 | |
| 241 | 261 | TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | |
| 242 | if (playing_notes) { | 262 | TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); |
| 243 | if (note_frequency > 0) { | 263 | } |
| 244 | #ifdef VIBRATO_ENABLE | 264 | } |
| 245 | if (vibrato_strength > 0) { | 265 | |
| 246 | freq = vibrato(note_frequency); | 266 | if (playing_notes) { |
| 247 | } else { | 267 | if (note_frequency > 0) { |
| 248 | freq = note_frequency; | 268 | #ifdef VIBRATO_ENABLE |
| 249 | } | 269 | if (vibrato_strength > 0) { |
| 250 | #else | 270 | freq = vibrato(note_frequency); |
| 251 | freq = note_frequency; | 271 | } else { |
| 252 | #endif | 272 | freq = note_frequency; |
| 253 | 273 | } | |
| 254 | if (envelope_index < 65535) { | 274 | #else |
| 255 | envelope_index++; | 275 | freq = note_frequency; |
| 256 | } | 276 | #endif |
| 257 | freq = voice_envelope(freq); | 277 | |
| 258 | 278 | if (envelope_index < 65535) { | |
| 259 | TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | 279 | envelope_index++; |
| 260 | TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); | 280 | } |
| 261 | } else { | 281 | freq = voice_envelope(freq); |
| 262 | TIMER_3_PERIOD = 0; | 282 | |
| 263 | TIMER_3_DUTY_CYCLE = 0; | 283 | TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); |
| 264 | } | 284 | TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); |
| 265 | 285 | } else { | |
| 266 | note_position++; | 286 | TIMER_3_PERIOD = 0; |
| 267 | bool end_of_note = false; | 287 | TIMER_3_DUTY_CYCLE = 0; |
| 268 | if (TIMER_3_PERIOD > 0) { | 288 | } |
| 269 | end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF)); | 289 | |
| 270 | } else { | 290 | note_position++; |
| 271 | end_of_note = (note_position >= (note_length * 0x7FF)); | 291 | bool end_of_note = false; |
| 272 | } | 292 | if (TIMER_3_PERIOD > 0) { |
| 273 | 293 | end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF)); | |
| 274 | if (end_of_note) { | 294 | } else { |
| 275 | current_note++; | 295 | end_of_note = (note_position >= (note_length * 0x7FF)); |
| 276 | if (current_note >= notes_count) { | 296 | } |
| 277 | if (notes_repeat) { | 297 | |
| 278 | current_note = 0; | 298 | if (end_of_note) { |
| 279 | } else { | 299 | current_note++; |
| 280 | DISABLE_AUDIO_COUNTER_3_ISR; | 300 | if (current_note >= notes_count) { |
| 281 | DISABLE_AUDIO_COUNTER_3_OUTPUT; | 301 | if (notes_repeat) { |
| 282 | playing_notes = false; | 302 | current_note = 0; |
| 283 | return; | 303 | } else { |
| 284 | } | 304 | DISABLE_AUDIO_COUNTER_3_ISR; |
| 285 | } | 305 | DISABLE_AUDIO_COUNTER_3_OUTPUT; |
| 286 | if (!note_resting && (notes_rest > 0)) { | 306 | playing_notes = false; |
| 287 | note_resting = true; | 307 | return; |
| 288 | note_frequency = 0; | 308 | } |
| 289 | note_length = notes_rest; | 309 | } |
| 290 | current_note--; | 310 | if (!note_resting && (notes_rest > 0)) { |
| 291 | } else { | 311 | note_resting = true; |
| 292 | note_resting = false; | 312 | note_frequency = 0; |
| 293 | envelope_index = 0; | 313 | note_length = notes_rest; |
| 294 | note_frequency = (*notes_pointer)[current_note][0]; | 314 | current_note--; |
| 295 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | 315 | } else { |
| 296 | } | 316 | note_resting = false; |
| 297 | 317 | envelope_index = 0; | |
| 298 | note_position = 0; | 318 | note_frequency = (*notes_pointer)[current_note][0]; |
| 299 | } | 319 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); |
| 300 | } | 320 | } |
| 301 | 321 | ||
| 302 | if (!audio_config.enable) { | 322 | note_position = 0; |
| 303 | playing_notes = false; | 323 | } |
| 304 | playing_note = false; | 324 | } |
| 305 | } | 325 | |
| 326 | if (!audio_config.enable) { | ||
| 327 | playing_notes = false; | ||
| 328 | playing_note = false; | ||
| 329 | } | ||
| 306 | } | 330 | } |
| 307 | 331 | ||
| 308 | void play_note(float freq, int vol) { | 332 | void play_note(float freq, int vol) { |
| 309 | 333 | ||
| 334 | dprintf("audio play note freq=%d vol=%d", (int)freq, vol); | ||
| 335 | |||
| 310 | if (!audio_initialized) { | 336 | if (!audio_initialized) { |
| 311 | audio_init(); | 337 | audio_init(); |
| 312 | } | 338 | } |
| 313 | 339 | ||
| 314 | if (audio_config.enable && voices < 8) { | 340 | if (audio_config.enable && voices < 8) { |
| 315 | DISABLE_AUDIO_COUNTER_3_ISR; | 341 | DISABLE_AUDIO_COUNTER_3_ISR; |
| 316 | 342 | ||
| 317 | // Cancel notes if notes are playing | 343 | // Cancel notes if notes are playing |
| 318 | if (playing_notes) | 344 | if (playing_notes) |
| 319 | stop_all_notes(); | 345 | stop_all_notes(); |
| 320 | 346 | ||
| 321 | playing_note = true; | 347 | playing_note = true; |
| 322 | 348 | ||
| 323 | envelope_index = 0; | 349 | envelope_index = 0; |
| 324 | 350 | ||
| 325 | if (freq > 0) { | 351 | if (freq > 0) { |
| 326 | frequencies[voices] = freq; | 352 | frequencies[voices] = freq; |
| 327 | volumes[voices] = vol; | 353 | volumes[voices] = vol; |
| 328 | voices++; | 354 | voices++; |
| 329 | } | 355 | } |
| 330 | 356 | ||
| 331 | ENABLE_AUDIO_COUNTER_3_ISR; | 357 | ENABLE_AUDIO_COUNTER_3_ISR; |
| 332 | ENABLE_AUDIO_COUNTER_3_OUTPUT; | 358 | ENABLE_AUDIO_COUNTER_3_OUTPUT; |
| 333 | } | 359 | } |
| 334 | 360 | ||
| 335 | } | 361 | } |
| 336 | 362 | ||
| @@ -341,37 +367,37 @@ void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) | |||
| 341 | audio_init(); | 367 | audio_init(); |
| 342 | } | 368 | } |
| 343 | 369 | ||
| 344 | if (audio_config.enable) { | 370 | if (audio_config.enable) { |
| 345 | 371 | ||
| 346 | DISABLE_AUDIO_COUNTER_3_ISR; | 372 | DISABLE_AUDIO_COUNTER_3_ISR; |
| 347 | 373 | ||
| 348 | // Cancel note if a note is playing | 374 | // Cancel note if a note is playing |
| 349 | if (playing_note) | 375 | if (playing_note) |
| 350 | stop_all_notes(); | 376 | stop_all_notes(); |
| 351 | 377 | ||
| 352 | playing_notes = true; | 378 | playing_notes = true; |
| 353 | 379 | ||
| 354 | notes_pointer = np; | 380 | notes_pointer = np; |
| 355 | notes_count = n_count; | 381 | notes_count = n_count; |
| 356 | notes_repeat = n_repeat; | 382 | notes_repeat = n_repeat; |
| 357 | notes_rest = n_rest; | 383 | notes_rest = n_rest; |
| 358 | 384 | ||
| 359 | place = 0; | 385 | place = 0; |
| 360 | current_note = 0; | 386 | current_note = 0; |
| 361 | 387 | ||
| 362 | note_frequency = (*notes_pointer)[current_note][0]; | 388 | note_frequency = (*notes_pointer)[current_note][0]; |
| 363 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | 389 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); |
| 364 | note_position = 0; | 390 | note_position = 0; |
| 365 | 391 | ||
| 366 | 392 | ||
| 367 | ENABLE_AUDIO_COUNTER_3_ISR; | 393 | ENABLE_AUDIO_COUNTER_3_ISR; |
| 368 | ENABLE_AUDIO_COUNTER_3_OUTPUT; | 394 | ENABLE_AUDIO_COUNTER_3_OUTPUT; |
| 369 | } | 395 | } |
| 370 | 396 | ||
| 371 | } | 397 | } |
| 372 | 398 | ||
| 373 | bool is_playing_notes(void) { | 399 | bool is_playing_notes(void) { |
| 374 | return playing_notes; | 400 | return playing_notes; |
| 375 | } | 401 | } |
| 376 | 402 | ||
| 377 | bool is_audio_on(void) { | 403 | bool is_audio_on(void) { |
