aboutsummaryrefslogtreecommitdiff
path: root/quantum/audio/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/audio/audio.c')
-rw-r--r--quantum/audio/audio.c334
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;
77audio_config_t audio_config; 92audio_config_t audio_config;
78 93
79uint16_t envelope_index = 0; 94uint16_t envelope_index = 0;
95bool glissando = true;
80 96
81void audio_init() 97void 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
106void stop_all_notes() 122void 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
128void stop_note(float freq) 146void 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
183ISR(TIMER3_COMPA_vect) 203ISR(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
308void play_note(float freq, int vol) { 332void 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
373bool is_playing_notes(void) { 399bool is_playing_notes(void) {
374 return playing_notes; 400 return playing_notes;
375} 401}
376 402
377bool is_audio_on(void) { 403bool is_audio_on(void) {