diff options
| author | Jack Humbert <jack.humb@gmail.com> | 2017-03-28 09:26:54 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-03-28 09:26:54 -0400 |
| commit | 7e37daa2ce6edad82de3835384176b51a8081537 (patch) | |
| tree | 58f349edb063667c9ae0affd99cec2bf7a7f93cb /quantum/audio | |
| parent | 216f669276b30393fb35a409011ccdad8b521156 (diff) | |
| parent | 0734f569409974624b40735fcd498dac9adba2d2 (diff) | |
| download | qmk_firmware-7e37daa2ce6edad82de3835384176b51a8081537.tar.gz qmk_firmware-7e37daa2ce6edad82de3835384176b51a8081537.zip | |
Merge pull request #1112 from newsboytko/newsboytko/midi-keycodes
Flesh out MIDI support
Diffstat (limited to 'quantum/audio')
| -rw-r--r-- | quantum/audio/audio.c | 322 |
1 files changed, 164 insertions, 158 deletions
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c index 2a315fd16..e1e81fd2b 100644 --- a/quantum/audio/audio.c +++ b/quantum/audio/audio.c | |||
| @@ -89,15 +89,15 @@ void audio_init() | |||
| 89 | } | 89 | } |
| 90 | audio_config.raw = eeconfig_read_audio(); | 90 | audio_config.raw = eeconfig_read_audio(); |
| 91 | 91 | ||
| 92 | // Set port PC6 (OC3A and /OC4A) as output | 92 | // Set port PC6 (OC3A and /OC4A) as output |
| 93 | DDRC |= _BV(PORTC6); | 93 | DDRC |= _BV(PORTC6); |
| 94 | 94 | ||
| 95 | DISABLE_AUDIO_COUNTER_3_ISR; | 95 | DISABLE_AUDIO_COUNTER_3_ISR; |
| 96 | 96 | ||
| 97 | // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers | 97 | // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers |
| 98 | // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 | 98 | // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 |
| 99 | // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A) | 99 | // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A) |
| 100 | // Clock Select (CS3n) = 0b010 = Clock / 8 | 100 | // Clock Select (CS3n) = 0b010 = Clock / 8 |
| 101 | TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); | 101 | TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); |
| 102 | TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); | 102 | TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); |
| 103 | 103 | ||
| @@ -106,6 +106,8 @@ void audio_init() | |||
| 106 | 106 | ||
| 107 | void stop_all_notes() | 107 | void stop_all_notes() |
| 108 | { | 108 | { |
| 109 | dprintf("audio stop all notes"); | ||
| 110 | |||
| 109 | if (!audio_initialized) { | 111 | if (!audio_initialized) { |
| 110 | audio_init(); | 112 | audio_init(); |
| 111 | } | 113 | } |
| @@ -128,6 +130,8 @@ void stop_all_notes() | |||
| 128 | 130 | ||
| 129 | void stop_note(float freq) | 131 | void stop_note(float freq) |
| 130 | { | 132 | { |
| 133 | dprintf("audio stop note freq=%d", (int)freq); | ||
| 134 | |||
| 131 | if (playing_note) { | 135 | if (playing_note) { |
| 132 | if (!audio_initialized) { | 136 | if (!audio_initialized) { |
| 133 | audio_init(); | 137 | audio_init(); |
| @@ -183,159 +187,161 @@ float vibrato(float average_freq) { | |||
| 183 | 187 | ||
| 184 | ISR(TIMER3_COMPA_vect) | 188 | ISR(TIMER3_COMPA_vect) |
| 185 | { | 189 | { |
| 186 | float freq; | 190 | float freq; |
| 187 | 191 | ||
| 188 | if (playing_note) { | 192 | if (playing_note) { |
| 189 | if (voices > 0) { | 193 | if (voices > 0) { |
| 190 | if (polyphony_rate > 0) { | 194 | if (polyphony_rate > 0) { |
| 191 | if (voices > 1) { | 195 | if (voices > 1) { |
| 192 | voice_place %= voices; | 196 | voice_place %= voices; |
| 193 | if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { | 197 | if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { |
| 194 | voice_place = (voice_place + 1) % voices; | 198 | voice_place = (voice_place + 1) % voices; |
| 195 | place = 0.0; | 199 | place = 0.0; |
| 196 | } | 200 | } |
| 197 | } | 201 | } |
| 198 | 202 | ||
| 199 | #ifdef VIBRATO_ENABLE | 203 | #ifdef VIBRATO_ENABLE |
| 200 | if (vibrato_strength > 0) { | 204 | if (vibrato_strength > 0) { |
| 201 | freq = vibrato(frequencies[voice_place]); | 205 | freq = vibrato(frequencies[voice_place]); |
| 202 | } else { | 206 | } else { |
| 203 | freq = frequencies[voice_place]; | 207 | freq = frequencies[voice_place]; |
| 204 | } | 208 | } |
| 205 | #else | 209 | #else |
| 206 | freq = frequencies[voice_place]; | 210 | freq = frequencies[voice_place]; |
| 207 | #endif | 211 | #endif |
| 208 | } else { | 212 | } else { |
| 209 | if (glissando) { | 213 | if (glissando) { |
| 210 | if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) { | 214 | if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) { |
| 211 | frequency = frequency * pow(2, 440/frequency/12/2); | 215 | frequency = frequency * pow(2, 440/frequency/12/2); |
| 212 | } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) { | 216 | } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) { |
| 213 | frequency = frequency * pow(2, -440/frequency/12/2); | 217 | frequency = frequency * pow(2, -440/frequency/12/2); |
| 214 | } else { | 218 | } else { |
| 215 | frequency = frequencies[voices - 1]; | 219 | frequency = frequencies[voices - 1]; |
| 216 | } | 220 | } |
| 217 | } else { | 221 | } else { |
| 218 | frequency = frequencies[voices - 1]; | 222 | frequency = frequencies[voices - 1]; |
| 219 | } | 223 | } |
| 220 | 224 | ||
| 221 | #ifdef VIBRATO_ENABLE | 225 | #ifdef VIBRATO_ENABLE |
| 222 | if (vibrato_strength > 0) { | 226 | if (vibrato_strength > 0) { |
| 223 | freq = vibrato(frequency); | 227 | freq = vibrato(frequency); |
| 224 | } else { | 228 | } else { |
| 225 | freq = frequency; | 229 | freq = frequency; |
| 226 | } | 230 | } |
| 227 | #else | 231 | #else |
| 228 | freq = frequency; | 232 | freq = frequency; |
| 229 | #endif | 233 | #endif |
| 230 | } | 234 | } |
| 231 | 235 | ||
| 232 | if (envelope_index < 65535) { | 236 | if (envelope_index < 65535) { |
| 233 | envelope_index++; | 237 | envelope_index++; |
| 234 | } | 238 | } |
| 235 | 239 | ||
| 236 | freq = voice_envelope(freq); | 240 | freq = voice_envelope(freq); |
| 237 | 241 | ||
| 238 | if (freq < 30.517578125) { | 242 | if (freq < 30.517578125) { |
| 239 | freq = 30.52; | 243 | freq = 30.52; |
| 240 | } | 244 | } |
| 241 | 245 | ||
| 242 | TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | 246 | TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); |
| 243 | TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); | 247 | TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); |
| 244 | } | 248 | } |
| 245 | } | 249 | } |
| 246 | 250 | ||
| 247 | if (playing_notes) { | 251 | if (playing_notes) { |
| 248 | if (note_frequency > 0) { | 252 | if (note_frequency > 0) { |
| 249 | #ifdef VIBRATO_ENABLE | 253 | #ifdef VIBRATO_ENABLE |
| 250 | if (vibrato_strength > 0) { | 254 | if (vibrato_strength > 0) { |
| 251 | freq = vibrato(note_frequency); | 255 | freq = vibrato(note_frequency); |
| 252 | } else { | 256 | } else { |
| 253 | freq = note_frequency; | 257 | freq = note_frequency; |
| 254 | } | 258 | } |
| 255 | #else | 259 | #else |
| 256 | freq = note_frequency; | 260 | freq = note_frequency; |
| 257 | #endif | 261 | #endif |
| 258 | 262 | ||
| 259 | if (envelope_index < 65535) { | 263 | if (envelope_index < 65535) { |
| 260 | envelope_index++; | 264 | envelope_index++; |
| 261 | } | 265 | } |
| 262 | freq = voice_envelope(freq); | 266 | freq = voice_envelope(freq); |
| 263 | 267 | ||
| 264 | TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | 268 | TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); |
| 265 | TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); | 269 | TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); |
| 266 | } else { | 270 | } else { |
| 267 | TIMER_3_PERIOD = 0; | 271 | TIMER_3_PERIOD = 0; |
| 268 | TIMER_3_DUTY_CYCLE = 0; | 272 | TIMER_3_DUTY_CYCLE = 0; |
| 269 | } | 273 | } |
| 270 | 274 | ||
| 271 | note_position++; | 275 | note_position++; |
| 272 | bool end_of_note = false; | 276 | bool end_of_note = false; |
| 273 | if (TIMER_3_PERIOD > 0) { | 277 | if (TIMER_3_PERIOD > 0) { |
| 274 | end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF)); | 278 | end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF)); |
| 275 | } else { | 279 | } else { |
| 276 | end_of_note = (note_position >= (note_length * 0x7FF)); | 280 | end_of_note = (note_position >= (note_length * 0x7FF)); |
| 277 | } | 281 | } |
| 278 | 282 | ||
| 279 | if (end_of_note) { | 283 | if (end_of_note) { |
| 280 | current_note++; | 284 | current_note++; |
| 281 | if (current_note >= notes_count) { | 285 | if (current_note >= notes_count) { |
| 282 | if (notes_repeat) { | 286 | if (notes_repeat) { |
| 283 | current_note = 0; | 287 | current_note = 0; |
| 284 | } else { | 288 | } else { |
| 285 | DISABLE_AUDIO_COUNTER_3_ISR; | 289 | DISABLE_AUDIO_COUNTER_3_ISR; |
| 286 | DISABLE_AUDIO_COUNTER_3_OUTPUT; | 290 | DISABLE_AUDIO_COUNTER_3_OUTPUT; |
| 287 | playing_notes = false; | 291 | playing_notes = false; |
| 288 | return; | 292 | return; |
| 289 | } | 293 | } |
| 290 | } | 294 | } |
| 291 | if (!note_resting && (notes_rest > 0)) { | 295 | if (!note_resting && (notes_rest > 0)) { |
| 292 | note_resting = true; | 296 | note_resting = true; |
| 293 | note_frequency = 0; | 297 | note_frequency = 0; |
| 294 | note_length = notes_rest; | 298 | note_length = notes_rest; |
| 295 | current_note--; | 299 | current_note--; |
| 296 | } else { | 300 | } else { |
| 297 | note_resting = false; | 301 | note_resting = false; |
| 298 | envelope_index = 0; | 302 | envelope_index = 0; |
| 299 | note_frequency = (*notes_pointer)[current_note][0]; | 303 | note_frequency = (*notes_pointer)[current_note][0]; |
| 300 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | 304 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); |
| 301 | } | 305 | } |
| 302 | 306 | ||
| 303 | note_position = 0; | 307 | note_position = 0; |
| 304 | } | 308 | } |
| 305 | } | 309 | } |
| 306 | 310 | ||
| 307 | if (!audio_config.enable) { | 311 | if (!audio_config.enable) { |
| 308 | playing_notes = false; | 312 | playing_notes = false; |
| 309 | playing_note = false; | 313 | playing_note = false; |
| 310 | } | 314 | } |
| 311 | } | 315 | } |
| 312 | 316 | ||
| 313 | void play_note(float freq, int vol) { | 317 | void play_note(float freq, int vol) { |
| 314 | 318 | ||
| 319 | dprintf("audio play note freq=%d vol=%d", (int)freq, vol); | ||
| 320 | |||
| 315 | if (!audio_initialized) { | 321 | if (!audio_initialized) { |
| 316 | audio_init(); | 322 | audio_init(); |
| 317 | } | 323 | } |
| 318 | 324 | ||
| 319 | if (audio_config.enable && voices < 8) { | 325 | if (audio_config.enable && voices < 8) { |
| 320 | DISABLE_AUDIO_COUNTER_3_ISR; | 326 | DISABLE_AUDIO_COUNTER_3_ISR; |
| 321 | 327 | ||
| 322 | // Cancel notes if notes are playing | 328 | // Cancel notes if notes are playing |
| 323 | if (playing_notes) | 329 | if (playing_notes) |
| 324 | stop_all_notes(); | 330 | stop_all_notes(); |
| 325 | 331 | ||
| 326 | playing_note = true; | 332 | playing_note = true; |
| 327 | 333 | ||
| 328 | envelope_index = 0; | 334 | envelope_index = 0; |
| 329 | 335 | ||
| 330 | if (freq > 0) { | 336 | if (freq > 0) { |
| 331 | frequencies[voices] = freq; | 337 | frequencies[voices] = freq; |
| 332 | volumes[voices] = vol; | 338 | volumes[voices] = vol; |
| 333 | voices++; | 339 | voices++; |
| 334 | } | 340 | } |
| 335 | 341 | ||
| 336 | ENABLE_AUDIO_COUNTER_3_ISR; | 342 | ENABLE_AUDIO_COUNTER_3_ISR; |
| 337 | ENABLE_AUDIO_COUNTER_3_OUTPUT; | 343 | ENABLE_AUDIO_COUNTER_3_OUTPUT; |
| 338 | } | 344 | } |
| 339 | 345 | ||
| 340 | } | 346 | } |
| 341 | 347 | ||
| @@ -346,37 +352,37 @@ void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) | |||
| 346 | audio_init(); | 352 | audio_init(); |
| 347 | } | 353 | } |
| 348 | 354 | ||
| 349 | if (audio_config.enable) { | 355 | if (audio_config.enable) { |
| 350 | 356 | ||
| 351 | DISABLE_AUDIO_COUNTER_3_ISR; | 357 | DISABLE_AUDIO_COUNTER_3_ISR; |
| 352 | 358 | ||
| 353 | // Cancel note if a note is playing | 359 | // Cancel note if a note is playing |
| 354 | if (playing_note) | 360 | if (playing_note) |
| 355 | stop_all_notes(); | 361 | stop_all_notes(); |
| 356 | 362 | ||
| 357 | playing_notes = true; | 363 | playing_notes = true; |
| 358 | 364 | ||
| 359 | notes_pointer = np; | 365 | notes_pointer = np; |
| 360 | notes_count = n_count; | 366 | notes_count = n_count; |
| 361 | notes_repeat = n_repeat; | 367 | notes_repeat = n_repeat; |
| 362 | notes_rest = n_rest; | 368 | notes_rest = n_rest; |
| 363 | 369 | ||
| 364 | place = 0; | 370 | place = 0; |
| 365 | current_note = 0; | 371 | current_note = 0; |
| 366 | 372 | ||
| 367 | note_frequency = (*notes_pointer)[current_note][0]; | 373 | note_frequency = (*notes_pointer)[current_note][0]; |
| 368 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | 374 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); |
| 369 | note_position = 0; | 375 | note_position = 0; |
| 370 | 376 | ||
| 371 | 377 | ||
| 372 | ENABLE_AUDIO_COUNTER_3_ISR; | 378 | ENABLE_AUDIO_COUNTER_3_ISR; |
| 373 | ENABLE_AUDIO_COUNTER_3_OUTPUT; | 379 | ENABLE_AUDIO_COUNTER_3_OUTPUT; |
| 374 | } | 380 | } |
| 375 | 381 | ||
| 376 | } | 382 | } |
| 377 | 383 | ||
| 378 | bool is_playing_notes(void) { | 384 | bool is_playing_notes(void) { |
| 379 | return playing_notes; | 385 | return playing_notes; |
| 380 | } | 386 | } |
| 381 | 387 | ||
| 382 | bool is_audio_on(void) { | 388 | bool is_audio_on(void) { |
