ft2_audio.c (26237B)
1 // for finding memory leaks in debug mode with Visual Studio 2 #if defined _DEBUG && defined _MSC_VER 3 #include <crtdbg.h> 4 #endif 5 6 #include <stdio.h> 7 #include <stdint.h> 8 #include "ft2_header.h" 9 #include "ft2_config.h" 10 #include "scopes/ft2_scopes.h" 11 #include "ft2_video.h" 12 #include "ft2_gui.h" 13 #include "ft2_midi.h" 14 #include "ft2_wav_renderer.h" 15 #include "ft2_tables.h" 16 #include "ft2_structs.h" 17 #include "ft2_audioselector.h" 18 #include "mixer/ft2_mix.h" 19 #include "mixer/ft2_silence_mix.h" 20 21 // hide POSIX warnings 22 #ifdef _MSC_VER 23 #pragma warning(disable: 4996) 24 #endif 25 26 static int32_t smpShiftValue; 27 static uint32_t oldAudioFreq, tickTimeLenInt; 28 static uint64_t tickTimeLenFrac; 29 static float fAudioNormalizeMul, fSqrtPanningTable[256+1]; 30 static voice_t voice[MAX_CHANNELS * 2]; 31 32 // globalized 33 audio_t audio; 34 pattSyncData_t *pattSyncEntry; 35 chSyncData_t *chSyncEntry; 36 chSync_t chSync; 37 pattSync_t pattSync; 38 volatile bool pattQueueClearing, chQueueClearing; 39 40 void stopVoice(int32_t i) 41 { 42 voice_t *v; 43 44 v = &voice[i]; 45 memset(v, 0, sizeof (voice_t)); 46 v->panning = 128; 47 48 // clear "fade out" voice too 49 50 v = &voice[MAX_CHANNELS + i]; 51 memset(v, 0, sizeof (voice_t)); 52 v->panning = 128; 53 } 54 55 bool setNewAudioSettings(void) // only call this from the main input/video thread 56 { 57 pauseAudio(); 58 59 if (!setupAudio(CONFIG_HIDE_ERRORS)) 60 { 61 // set back old known working settings 62 63 config.audioFreq = audio.lastWorkingAudioFreq; 64 config.specialFlags &= ~(BITDEPTH_16 + BITDEPTH_32 + BUFFSIZE_512 + BUFFSIZE_1024 + BUFFSIZE_2048); 65 config.specialFlags |= audio.lastWorkingAudioBits; 66 67 if (audio.lastWorkingAudioDeviceName != NULL) 68 { 69 if (audio.currOutputDevice != NULL) 70 { 71 free(audio.currOutputDevice); 72 audio.currOutputDevice = NULL; 73 } 74 75 audio.currOutputDevice = strdup(audio.lastWorkingAudioDeviceName); 76 } 77 78 // also update config audio radio buttons if we're on that screen at the moment 79 if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_AUDIO) 80 setConfigAudioRadioButtonStates(); 81 82 // if it didn't work to use the old settings again, then something is seriously wrong... 83 if (!setupAudio(CONFIG_HIDE_ERRORS)) 84 okBox(0, "System message", "Couldn't find a working audio mode... You'll get no sound / replayer timer!", NULL); 85 86 resumeAudio(); 87 return false; 88 } 89 90 resumeAudio(); 91 92 setWavRenderFrequency(audio.freq); 93 setWavRenderBitDepth((config.specialFlags & BITDEPTH_32) ? 32 : 16); 94 return true; 95 } 96 97 // amp = 1..32, masterVol = 0..256 98 void setAudioAmp(int16_t amp, int16_t masterVol, bool bitDepth32Flag) 99 { 100 amp = CLAMP(amp, 1, 32); 101 masterVol = CLAMP(masterVol, 0, 256); 102 103 double dAmp = (amp * masterVol) / (32.0 * 256.0); 104 if (!bitDepth32Flag) 105 dAmp *= 32768.0; 106 107 fAudioNormalizeMul = (float)dAmp; 108 } 109 110 void decreaseMasterVol(void) 111 { 112 if (config.masterVol >= 16) 113 config.masterVol -= 16; 114 else 115 config.masterVol = 0; 116 117 setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32)); 118 119 // if Config -> Audio is open, update master volume scrollbar 120 if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_AUDIO) 121 drawScrollBar(SB_MASTERVOL_SCROLL); 122 } 123 124 void increaseMasterVol(void) 125 { 126 if (config.masterVol < (256-16)) 127 config.masterVol += 16; 128 else 129 config.masterVol = 256; 130 131 setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32)); 132 133 // if Config -> Audio is open, update master volume scrollbar 134 if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_AUDIO) 135 drawScrollBar(SB_MASTERVOL_SCROLL); 136 } 137 138 void setNewAudioFreq(uint32_t freq) // for song-to-WAV rendering 139 { 140 if (freq == 0) 141 return; 142 143 oldAudioFreq = audio.freq; 144 audio.freq = freq; 145 146 const bool mustRecalcTables = audio.freq != oldAudioFreq; 147 if (mustRecalcTables) 148 calcReplayerVars(audio.freq); 149 } 150 151 void setBackOldAudioFreq(void) // for song-to-WAV rendering 152 { 153 const bool mustRecalcTables = audio.freq != oldAudioFreq; 154 155 audio.freq = oldAudioFreq; 156 157 if (mustRecalcTables) 158 calcReplayerVars(audio.freq); 159 } 160 161 void setMixerBPM(int32_t bpm) 162 { 163 if (bpm < MIN_BPM || bpm > MAX_BPM) 164 return; 165 166 int32_t i = bpm - MIN_BPM; 167 168 audio.samplesPerTickInt = audio.samplesPerTickIntTab[i]; 169 audio.samplesPerTickFrac = audio.samplesPerTickFracTab[i]; 170 audio.fSamplesPerTickIntMul = (float)(1.0 / (double)audio.samplesPerTickInt); 171 172 // for audio/video sync timestamp 173 tickTimeLenInt = audio.tickTimeIntTab[i]; 174 tickTimeLenFrac = audio.tickTimeFracTab[i]; 175 } 176 177 void audioSetVolRamp(bool volRamp) 178 { 179 lockMixerCallback(); 180 audio.volumeRampingFlag = volRamp; 181 unlockMixerCallback(); 182 } 183 184 void audioSetInterpolationType(uint8_t interpolationType) 185 { 186 lockMixerCallback(); 187 audio.interpolationType = interpolationType; 188 189 audio.sincInterpolation = false; 190 191 // set sinc LUT pointers 192 if (config.interpolation == INTERPOLATION_SINC8) 193 { 194 fSinc_1 = fSinc8_1; 195 fSinc_2 = fSinc8_2; 196 fSinc_3 = fSinc8_3; 197 198 audio.sincInterpolation = true; 199 } 200 else if (config.interpolation == INTERPOLATION_SINC16) 201 { 202 fSinc_1 = fSinc16_1; 203 fSinc_2 = fSinc16_2; 204 fSinc_3 = fSinc16_3; 205 206 audio.sincInterpolation = true; 207 } 208 209 unlockMixerCallback(); 210 } 211 212 void calcPanningTable(void) 213 { 214 // same formula as FT2's panning table (with 0.0 .. 1.0 scale) 215 for (int32_t i = 0; i <= 256; i++) 216 fSqrtPanningTable[i] = (float)sqrt(i / 256.0); 217 } 218 219 static void voiceUpdateVolumes(int32_t i, uint8_t status) 220 { 221 voice_t *v = &voice[i]; 222 223 v->fTargetVolumeL = v->fVolume * fSqrtPanningTable[256-v->panning]; 224 v->fTargetVolumeR = v->fVolume * fSqrtPanningTable[ v->panning]; 225 226 if (!audio.volumeRampingFlag) 227 { 228 // volume ramping is disabled, set volume directly 229 v->fCurrVolumeL = v->fTargetVolumeL; 230 v->fCurrVolumeR = v->fTargetVolumeR; 231 v->volumeRampLength = 0; 232 return; 233 } 234 235 // now we need to handle volume ramping 236 237 const bool voiceSampleTrigger = !!(status & IS_Trigger); 238 239 if (voiceSampleTrigger) 240 { 241 // sample is about to start, ramp out/in at the same time 242 243 if (v->fCurrVolumeL > 0.0f || v->fCurrVolumeR > 0.0f) 244 { 245 // setup fadeout voice 246 247 voice_t *f = &voice[MAX_CHANNELS+i]; 248 249 *f = *v; // copy current voice to new fadeout-ramp voice 250 251 const float fVolumeLDiff = 0.0f - f->fCurrVolumeL; 252 const float fVolumeRDiff = 0.0f - f->fCurrVolumeR; 253 254 f->volumeRampLength = audio.quickVolRampSamples; // 5ms 255 f->fVolumeLDelta = fVolumeLDiff * audio.fQuickVolRampSamplesMul; 256 f->fVolumeRDelta = fVolumeRDiff * audio.fQuickVolRampSamplesMul; 257 258 f->isFadeOutVoice = true; 259 } 260 261 // make current voice fade in from zero when it starts 262 v->fCurrVolumeL = v->fCurrVolumeR = 0.0f; 263 } 264 265 if (!voiceSampleTrigger && v->fTargetVolumeL == v->fCurrVolumeL && v->fTargetVolumeR == v->fCurrVolumeR) 266 { 267 v->volumeRampLength = 0; // no ramp needed for now 268 } 269 else 270 { 271 const float fVolumeLDiff = v->fTargetVolumeL - v->fCurrVolumeL; 272 const float fVolumeRDiff = v->fTargetVolumeR - v->fCurrVolumeR; 273 274 float fRampLengthMul; 275 if (status & IS_QuickVol) // duration of 5ms 276 { 277 v->volumeRampLength = audio.quickVolRampSamples; 278 fRampLengthMul = audio.fQuickVolRampSamplesMul; 279 } 280 else // duration of a tick 281 { 282 v->volumeRampLength = audio.samplesPerTickInt; 283 fRampLengthMul = audio.fSamplesPerTickIntMul; 284 } 285 286 v->fVolumeLDelta = fVolumeLDiff * fRampLengthMul; 287 v->fVolumeRDelta = fVolumeRDiff * fRampLengthMul; 288 } 289 } 290 291 static void voiceTrigger(int32_t ch, sample_t *s, int32_t position) 292 { 293 voice_t *v = &voice[ch]; 294 295 int32_t length = s->length; 296 int32_t loopStart = s->loopStart; 297 int32_t loopLength = s->loopLength; 298 int32_t loopEnd = s->loopStart + s->loopLength; 299 uint8_t loopType = GET_LOOPTYPE(s->flags); 300 bool sample16Bit = !!(s->flags & SAMPLE_16BIT); 301 302 if (s->dataPtr == NULL || length < 1) 303 { 304 v->active = false; // shut down voice (illegal parameters) 305 return; 306 } 307 308 if (loopLength < 1) // disable loop if loopLength is below 1 309 loopType = 0; 310 311 if (sample16Bit) 312 { 313 v->base16 = (const int16_t *)s->dataPtr; 314 v->revBase16 = &v->base16[loopStart + loopEnd]; // for pingpong loops 315 v->leftEdgeTaps16 = s->leftEdgeTapSamples16 + MAX_LEFT_TAPS; 316 } 317 else 318 { 319 v->base8 = s->dataPtr; 320 v->revBase8 = &v->base8[loopStart + loopEnd]; // for pingpong loops 321 v->leftEdgeTaps8 = s->leftEdgeTapSamples8 + MAX_LEFT_TAPS; 322 } 323 324 v->hasLooped = false; // for cubic/sinc interpolation special case 325 v->samplingBackwards = false; 326 v->loopType = loopType; 327 v->sampleEnd = (loopType == LOOP_OFF) ? length : loopEnd; 328 v->loopStart = loopStart; 329 v->loopLength = loopLength; 330 v->position = position; 331 v->positionFrac = 0; 332 333 // if position overflows, shut down voice (f.ex. through 9xx command) 334 if (v->position >= v->sampleEnd) 335 { 336 v->active = false; 337 return; 338 } 339 340 v->mixFuncOffset = ((int32_t)sample16Bit * 18) + (audio.interpolationType * 3) + loopType; 341 v->active = true; 342 } 343 344 void resetRampVolumes(void) 345 { 346 voice_t *v = voice; 347 for (int32_t i = 0; i < song.numChannels; i++, v++) 348 { 349 v->fCurrVolumeL = v->fTargetVolumeL; 350 v->fCurrVolumeR = v->fTargetVolumeR; 351 v->volumeRampLength = 0; 352 } 353 } 354 355 void updateVoices(void) 356 { 357 channel_t *ch = channel; 358 voice_t *v = voice; 359 360 for (int32_t i = 0; i < song.numChannels; i++, ch++, v++) 361 { 362 const uint8_t status = ch->tmpStatus = ch->status; // (tmpStatus is used for audio/video sync queue) 363 if (status == 0) 364 continue; 365 366 ch->status = 0; 367 368 if (status & IS_Vol) 369 { 370 v->fVolume = ch->fFinalVol; // 0.0f .. 1.0f 371 v->scopeVolume = (uint8_t)((ch->fFinalVol * 255.0f) + 0.5f); // 0..255, rounded 372 } 373 374 if (status & IS_Pan) 375 v->panning = ch->finalPan; 376 377 if (status & (IS_Vol + IS_Pan)) 378 voiceUpdateVolumes(i, status); 379 380 if (status & IS_Period) 381 { 382 const double dVoiceHz = dPeriod2Hz(ch->finalPeriod); 383 384 // set voice delta 385 v->delta = (int64_t)((dVoiceHz * audio.dHz2MixDeltaMul) + 0.5); // Hz -> fixed-point delta (rounded) 386 if (audio.sincInterpolation) 387 { 388 // decide which sinc LUT to use according to the resampling ratio 389 if (v->delta <= sincRatio1) 390 v->fSincLUT = fSinc_1; 391 else if (v->delta <= sincRatio2) 392 v->fSincLUT = fSinc_2; 393 else 394 v->fSincLUT = fSinc_3; 395 } 396 } 397 398 if (status & IS_Trigger) 399 voiceTrigger(i, ch->smpPtr, ch->smpStartPos); 400 } 401 } 402 403 static void sendSamples16BitStereo(void *stream, uint32_t sampleBlockLength) 404 { 405 int16_t *streamPtr16 = (int16_t *)stream; 406 for (uint32_t i = 0; i < sampleBlockLength; i++) 407 { 408 int32_t L = (int32_t)(audio.fMixBufferL[i] * fAudioNormalizeMul); 409 int32_t R = (int32_t)(audio.fMixBufferR[i] * fAudioNormalizeMul); 410 411 CLAMP16(L); 412 CLAMP16(R); 413 414 *streamPtr16++ = (int16_t)L; 415 *streamPtr16++ = (int16_t)R; 416 417 // clear what we read from the mixing buffer 418 audio.fMixBufferL[i] = audio.fMixBufferR[i] = 0.0f; 419 } 420 } 421 422 static void sendSamples32BitFloatStereo(void *stream, uint32_t sampleBlockLength) 423 { 424 float *fStreamPtr32 = (float *)stream; 425 for (uint32_t i = 0; i < sampleBlockLength; i++) 426 { 427 const float fL = audio.fMixBufferL[i] * fAudioNormalizeMul; 428 const float fR = audio.fMixBufferR[i] * fAudioNormalizeMul; 429 430 *fStreamPtr32++ = CLAMP(fL, -1.0f, 1.0f); 431 *fStreamPtr32++ = CLAMP(fR, -1.0f, 1.0f); 432 433 // clear what we read from the mixing buffer 434 audio.fMixBufferL[i] = audio.fMixBufferR[i] = 0.0f; 435 } 436 } 437 438 static void doChannelMixing(int32_t bufferPosition, int32_t samplesToMix) 439 { 440 voice_t *v = voice; // normal voices 441 voice_t *r = &voice[MAX_CHANNELS]; // volume ramp fadeout-voices 442 443 const int32_t mixOffsetBias = 3 * NUM_INTERPOLATORS * 2; // 3 = loop types (off/fwd/bidi), 2 = bit depths (8-bit/16-bit) 444 445 for (int32_t i = 0; i < song.numChannels; i++, v++, r++) 446 { 447 if (v->active) 448 { 449 const bool volRampFlag = (v->volumeRampLength > 0); 450 if (!volRampFlag && v->fCurrVolumeL == 0.0f && v->fCurrVolumeR == 0.0f) 451 silenceMixRoutine(v, samplesToMix); 452 else 453 mixFuncTab[((int32_t)volRampFlag * mixOffsetBias) + v->mixFuncOffset](v, bufferPosition, samplesToMix); 454 } 455 456 if (r->active) // volume ramp fadeout-voice 457 mixFuncTab[mixOffsetBias + r->mixFuncOffset](r, bufferPosition, samplesToMix); 458 } 459 } 460 461 // used for song-to-WAV renderer 462 void mixReplayerTickToBuffer(uint32_t samplesToMix, void *stream, uint8_t bitDepth) 463 { 464 doChannelMixing(0, samplesToMix); 465 466 // normalize mix buffer and send to audio stream 467 if (bitDepth == 16) 468 sendSamples16BitStereo(stream, samplesToMix); 469 else 470 sendSamples32BitFloatStereo(stream, samplesToMix); 471 } 472 473 int32_t pattQueueReadSize(void) 474 { 475 while (pattQueueClearing); 476 477 if (pattSync.writePos > pattSync.readPos) 478 return pattSync.writePos - pattSync.readPos; 479 else if (pattSync.writePos < pattSync.readPos) 480 return pattSync.writePos - pattSync.readPos + SYNC_QUEUE_LEN + 1; 481 else 482 return 0; 483 } 484 485 int32_t pattQueueWriteSize(void) 486 { 487 int32_t size; 488 489 if (pattSync.writePos > pattSync.readPos) 490 { 491 size = pattSync.readPos - pattSync.writePos + SYNC_QUEUE_LEN; 492 } 493 else if (pattSync.writePos < pattSync.readPos) 494 { 495 pattQueueClearing = true; 496 497 /* Buffer is full, reset the read/write pos. This is actually really nasty since 498 ** read/write are two different threads, but because of timestamp validation it 499 ** shouldn't be that dangerous. 500 ** It will also create a small visual stutter while the buffer is getting filled, 501 ** though that is barely noticable on normal buffer sizes, and it takes a minute 502 ** or two at max BPM between each time (when queue size is default, 4095) 503 */ 504 pattSync.data[0].timestamp = 0; 505 pattSync.readPos = 0; 506 pattSync.writePos = 0; 507 508 size = SYNC_QUEUE_LEN; 509 510 pattQueueClearing = false; 511 } 512 else 513 { 514 size = SYNC_QUEUE_LEN; 515 } 516 517 return size; 518 } 519 520 bool pattQueuePush(pattSyncData_t t) 521 { 522 if (!pattQueueWriteSize()) 523 return false; 524 525 assert(pattSync.writePos <= SYNC_QUEUE_LEN); 526 pattSync.data[pattSync.writePos] = t; 527 pattSync.writePos = (pattSync.writePos + 1) & SYNC_QUEUE_LEN; 528 529 return true; 530 } 531 532 bool pattQueuePop(void) 533 { 534 if (!pattQueueReadSize()) 535 return false; 536 537 pattSync.readPos = (pattSync.readPos + 1) & SYNC_QUEUE_LEN; 538 assert(pattSync.readPos <= SYNC_QUEUE_LEN); 539 540 return true; 541 } 542 543 pattSyncData_t *pattQueuePeek(void) 544 { 545 if (!pattQueueReadSize()) 546 return NULL; 547 548 assert(pattSync.readPos <= SYNC_QUEUE_LEN); 549 return &pattSync.data[pattSync.readPos]; 550 } 551 552 uint64_t getPattQueueTimestamp(void) 553 { 554 if (!pattQueueReadSize()) 555 return 0; 556 557 assert(pattSync.readPos <= SYNC_QUEUE_LEN); 558 return pattSync.data[pattSync.readPos].timestamp; 559 } 560 561 int32_t chQueueReadSize(void) 562 { 563 while (chQueueClearing); 564 565 if (chSync.writePos > chSync.readPos) 566 return chSync.writePos - chSync.readPos; 567 else if (chSync.writePos < chSync.readPos) 568 return chSync.writePos - chSync.readPos + SYNC_QUEUE_LEN + 1; 569 else 570 return 0; 571 } 572 573 int32_t chQueueWriteSize(void) 574 { 575 int32_t size; 576 577 if (chSync.writePos > chSync.readPos) 578 { 579 size = chSync.readPos - chSync.writePos + SYNC_QUEUE_LEN; 580 } 581 else if (chSync.writePos < chSync.readPos) 582 { 583 chQueueClearing = true; 584 585 /* Buffer is full, reset the read/write pos. This is actually really nasty since 586 ** read/write are two different threads, but because of timestamp validation it 587 ** shouldn't be that dangerous. 588 ** It will also create a small visual stutter while the buffer is getting filled, 589 ** though that is barely noticable on normal buffer sizes, and it takes several 590 ** minutes between each time (when queue size is default, 16384) 591 */ 592 chSync.data[0].timestamp = 0; 593 chSync.readPos = 0; 594 chSync.writePos = 0; 595 596 size = SYNC_QUEUE_LEN; 597 598 chQueueClearing = false; 599 } 600 else 601 { 602 size = SYNC_QUEUE_LEN; 603 } 604 605 return size; 606 } 607 608 bool chQueuePush(chSyncData_t t) 609 { 610 if (!chQueueWriteSize()) 611 return false; 612 613 assert(chSync.writePos <= SYNC_QUEUE_LEN); 614 chSync.data[chSync.writePos] = t; 615 chSync.writePos = (chSync.writePos + 1) & SYNC_QUEUE_LEN; 616 617 return true; 618 } 619 620 bool chQueuePop(void) 621 { 622 if (!chQueueReadSize()) 623 return false; 624 625 chSync.readPos = (chSync.readPos + 1) & SYNC_QUEUE_LEN; 626 assert(chSync.readPos <= SYNC_QUEUE_LEN); 627 628 return true; 629 } 630 631 chSyncData_t *chQueuePeek(void) 632 { 633 if (!chQueueReadSize()) 634 return NULL; 635 636 assert(chSync.readPos <= SYNC_QUEUE_LEN); 637 return &chSync.data[chSync.readPos]; 638 } 639 640 uint64_t getChQueueTimestamp(void) 641 { 642 if (!chQueueReadSize()) 643 return 0; 644 645 assert(chSync.readPos <= SYNC_QUEUE_LEN); 646 return chSync.data[chSync.readPos].timestamp; 647 } 648 649 void lockAudio(void) 650 { 651 if (audio.dev != 0) 652 SDL_LockAudioDevice(audio.dev); 653 654 audio.locked = true; 655 } 656 657 void unlockAudio(void) 658 { 659 if (audio.dev != 0) 660 SDL_UnlockAudioDevice(audio.dev); 661 662 audio.locked = false; 663 } 664 665 void resetSyncQueues(void) 666 { 667 pattSync.data[0].timestamp = 0; 668 pattSync.readPos = 0; 669 pattSync.writePos = 0; 670 671 chSync.data[0].timestamp = 0; 672 chSync.writePos = 0; 673 chSync.readPos = 0; 674 } 675 676 void lockMixerCallback(void) // lock audio + clear voices/scopes (for short operations) 677 { 678 if (!audio.locked) 679 lockAudio(); 680 681 audio.resetSyncTickTimeFlag = true; 682 683 stopVoices(); // VERY important! prevents potential crashes by purging pointers 684 685 // scopes, mixer and replayer are guaranteed to not be active at this point 686 687 resetSyncQueues(); 688 } 689 690 void unlockMixerCallback(void) 691 { 692 stopVoices(); // VERY important! prevents potential crashes by purging pointers 693 694 if (audio.locked) 695 unlockAudio(); 696 } 697 698 void pauseAudio(void) // lock audio + clear voices/scopes + render silence (for long operations) 699 { 700 if (audioPaused) 701 { 702 stopVoices(); // VERY important! prevents potential crashes by purging pointers 703 return; 704 } 705 706 if (audio.dev > 0) 707 SDL_PauseAudioDevice(audio.dev, true); 708 709 audio.resetSyncTickTimeFlag = true; 710 711 stopVoices(); // VERY important! prevents potential crashes by purging pointers 712 713 // scopes, mixer and replayer are guaranteed to not be active at this point 714 715 resetSyncQueues(); 716 audioPaused = true; 717 } 718 719 void resumeAudio(void) // unlock audio 720 { 721 if (!audioPaused) 722 return; 723 724 if (audio.dev > 0) 725 SDL_PauseAudioDevice(audio.dev, false); 726 727 audioPaused = false; 728 } 729 730 static void fillVisualsSyncBuffer(void) 731 { 732 pattSyncData_t pattSyncData; 733 chSyncData_t chSyncData; 734 735 if (audio.resetSyncTickTimeFlag) 736 { 737 audio.resetSyncTickTimeFlag = false; 738 739 audio.tickTime64 = SDL_GetPerformanceCounter() + audio.audLatencyPerfValInt; 740 audio.tickTime64Frac = audio.audLatencyPerfValFrac; 741 } 742 743 if (songPlaying) 744 { 745 // push pattern variables to sync queue 746 pattSyncData.tick = song.curReplayerTick; 747 pattSyncData.row = song.curReplayerRow; 748 pattSyncData.pattNum = song.curReplayerPattNum; 749 pattSyncData.songPos = song.curReplayerSongPos; 750 pattSyncData.BPM = (uint8_t)song.BPM; 751 pattSyncData.speed = (uint8_t)song.speed; 752 pattSyncData.globalVolume = (uint8_t)song.globalVolume; 753 pattSyncData.timestamp = audio.tickTime64; 754 pattQueuePush(pattSyncData); 755 } 756 757 // push channel variables to sync queue 758 759 syncedChannel_t *c = chSyncData.channels; 760 channel_t *s = channel; 761 voice_t *v = voice; 762 763 for (int32_t i = 0; i < song.numChannels; i++, c++, s++, v++) 764 { 765 c->scopeVolume = v->scopeVolume; 766 c->period = s->finalPeriod; 767 c->instrNum = s->instrNum; 768 c->smpNum = s->smpNum; 769 c->status = s->tmpStatus; 770 c->smpStartPos = s->smpStartPos; 771 772 c->pianoNoteNum = 255; // no piano key 773 if (songPlaying && ui.instEditorShown && (c->status & IS_Period) && !s->keyOff) 774 { 775 const int32_t note = getPianoKey(s->finalPeriod, s->finetune, s->relativeNote); 776 if (note >= 0 && note <= 95) 777 c->pianoNoteNum = (uint8_t)note; 778 } 779 } 780 781 chSyncData.timestamp = audio.tickTime64; 782 chQueuePush(chSyncData); 783 784 audio.tickTime64 += tickTimeLenInt; 785 786 audio.tickTime64Frac += tickTimeLenFrac; 787 if (audio.tickTime64Frac >= TICK_TIME_FRAC_SCALE) 788 { 789 audio.tickTime64Frac &= TICK_TIME_FRAC_MASK; 790 audio.tickTime64++; 791 } 792 } 793 794 static void SDLCALL audioCallback(void *userdata, Uint8 *stream, int len) 795 { 796 if (editor.wavIsRendering) 797 return; 798 799 len >>= smpShiftValue; // bytes -> samples 800 if (len <= 0) 801 return; 802 803 int32_t bufferPosition = 0; 804 805 uint32_t samplesLeft = len; 806 while (samplesLeft > 0) 807 { 808 if (audio.tickSampleCounter == 0) // new replayer tick 809 { 810 replayerBusy = true; 811 if (!musicPaused) // important, don't remove this check! (also used for safety) 812 { 813 if (audio.volumeRampingFlag) 814 resetRampVolumes(); 815 816 tickReplayer(); 817 updateVoices(); 818 fillVisualsSyncBuffer(); 819 } 820 replayerBusy = false; 821 822 audio.tickSampleCounter = audio.samplesPerTickInt; 823 824 audio.tickSampleCounterFrac += audio.samplesPerTickFrac; 825 if (audio.tickSampleCounterFrac >= BPM_FRAC_SCALE) 826 { 827 audio.tickSampleCounterFrac &= BPM_FRAC_MASK; 828 audio.tickSampleCounter++; 829 } 830 } 831 832 uint32_t samplesToMix = samplesLeft; 833 if (samplesToMix > audio.tickSampleCounter) 834 samplesToMix = audio.tickSampleCounter; 835 836 doChannelMixing(bufferPosition, samplesToMix); 837 bufferPosition += samplesToMix; 838 839 audio.tickSampleCounter -= samplesToMix; 840 samplesLeft -= samplesToMix; 841 } 842 843 if (config.specialFlags & BITDEPTH_16) 844 sendSamples16BitStereo(stream, len); 845 else 846 sendSamples32BitFloatStereo(stream, len); 847 848 (void)userdata; 849 } 850 851 static bool setupAudioBuffers(void) 852 { 853 const int32_t maxAudioFreq = MAX(MAX_AUDIO_FREQ, MAX_WAV_RENDER_FREQ); 854 int32_t maxSamplesPerTick = (int32_t)ceil(maxAudioFreq / (MIN_BPM / 2.5)) + 1; 855 856 audio.fMixBufferL = (float *)calloc(maxSamplesPerTick, sizeof (float)); 857 audio.fMixBufferR = (float *)calloc(maxSamplesPerTick, sizeof (float)); 858 859 if (audio.fMixBufferL == NULL || audio.fMixBufferR == NULL) 860 return false; 861 862 return true; 863 } 864 865 static void freeAudioBuffers(void) 866 { 867 if (audio.fMixBufferL != NULL) 868 { 869 free(audio.fMixBufferL); 870 audio.fMixBufferL = NULL; 871 } 872 873 if (audio.fMixBufferR != NULL) 874 { 875 free(audio.fMixBufferR); 876 audio.fMixBufferR = NULL; 877 } 878 } 879 880 static void calcAudioLatencyVars(int32_t audioBufferSize, int32_t audioFreq) 881 { 882 double dInt; 883 884 if (audioFreq == 0) 885 return; 886 887 const double dAudioLatencySecs = audioBufferSize / (double)audioFreq; 888 889 double dFrac = modf(dAudioLatencySecs * editor.dPerfFreq, &dInt); 890 891 audio.audLatencyPerfValInt = (uint32_t)dInt; 892 audio.audLatencyPerfValFrac = (uint64_t)((dFrac * TICK_TIME_FRAC_SCALE) + 0.5); // rounded 893 } 894 895 static void setLastWorkingAudioDevName(void) 896 { 897 if (audio.lastWorkingAudioDeviceName != NULL) 898 { 899 free(audio.lastWorkingAudioDeviceName); 900 audio.lastWorkingAudioDeviceName = NULL; 901 } 902 903 if (audio.currOutputDevice != NULL) 904 audio.lastWorkingAudioDeviceName = strdup(audio.currOutputDevice); 905 } 906 907 bool setupAudio(bool showErrorMsg) 908 { 909 SDL_AudioSpec want, have; 910 911 closeAudio(); 912 913 if (config.audioFreq < MIN_AUDIO_FREQ || config.audioFreq > MAX_AUDIO_FREQ) 914 config.audioFreq = DEFAULT_AUDIO_FREQ; 915 916 // get audio buffer size from config special flags 917 918 uint16_t configAudioBufSize = 1024; 919 if (config.specialFlags & BUFFSIZE_512) 920 configAudioBufSize = 512; 921 else if (config.specialFlags & BUFFSIZE_2048) 922 configAudioBufSize = 2048; 923 924 audio.wantFreq = config.audioFreq; 925 audio.wantSamples = configAudioBufSize; 926 927 // set up audio device 928 memset(&want, 0, sizeof (want)); 929 want.freq = config.audioFreq; 930 want.format = (config.specialFlags & BITDEPTH_32) ? AUDIO_F32 : AUDIO_S16; 931 want.channels = 2; 932 want.callback = audioCallback; 933 want.samples = configAudioBufSize; 934 935 char *device = audio.currOutputDevice; 936 if (device != NULL && strcmp(device, DEFAULT_AUDIO_DEV_STR) == 0) 937 device = NULL; // force default device 938 939 audio.dev = SDL_OpenAudioDevice(device, 0, &want, &have, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); 940 if (audio.dev == 0) 941 { 942 audio.dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); 943 if (audio.currOutputDevice != NULL) 944 { 945 free(audio.currOutputDevice); 946 audio.currOutputDevice = NULL; 947 } 948 audio.currOutputDevice = strdup(DEFAULT_AUDIO_DEV_STR); 949 950 if (audio.dev == 0) 951 { 952 if (showErrorMsg) 953 showErrorMsgBox("Couldn't open audio device:\n\"%s\"\n\nDo you have an audio device enabled and plugged in?", SDL_GetError()); 954 955 return false; 956 } 957 } 958 959 // test if the received audio format is compatible 960 if (have.format != AUDIO_S16 && have.format != AUDIO_F32) 961 { 962 if (showErrorMsg) 963 showErrorMsgBox("Couldn't open audio device:\nThis program only supports 16-bit or 32-bit float audio streams. Sorry!"); 964 965 closeAudio(); 966 return false; 967 } 968 969 // test if the received audio stream is compatible 970 971 if (have.channels != 2) 972 { 973 if (showErrorMsg) 974 showErrorMsgBox("Couldn't open audio device:\nThis program only supports stereo audio streams. Sorry!"); 975 976 closeAudio(); 977 return false; 978 } 979 980 /* 981 if (have.freq != 44100 && have.freq != 48000 && have.freq != 96000) 982 { 983 if (showErrorMsg) 984 showErrorMsgBox("Couldn't open audio device:\nThis program doesn't support an audio output rate of %dHz. Sorry!", have.freq); 985 986 closeAudio(); 987 return false; 988 } 989 */ 990 991 if (!setupAudioBuffers()) 992 { 993 if (showErrorMsg) 994 showErrorMsgBox("Not enough memory!"); 995 996 closeAudio(); 997 return false; 998 } 999 1000 // set new bit depth flag 1001 1002 int8_t newBitDepth = 16; 1003 config.specialFlags &= ~BITDEPTH_32; 1004 config.specialFlags |= BITDEPTH_16; 1005 1006 if (have.format == AUDIO_F32) 1007 { 1008 newBitDepth = 24; 1009 config.specialFlags &= ~BITDEPTH_16; 1010 config.specialFlags |= BITDEPTH_32; 1011 } 1012 1013 audio.haveFreq = have.freq; 1014 audio.haveSamples = have.samples; 1015 config.audioFreq = audio.freq = have.freq; 1016 1017 calcAudioLatencyVars(have.samples, have.freq); 1018 smpShiftValue = (newBitDepth == 16) ? 2 : 3; 1019 1020 // make a copy of the new known working audio settings 1021 1022 audio.lastWorkingAudioFreq = config.audioFreq; 1023 audio.lastWorkingAudioBits = config.specialFlags & (BITDEPTH_16 + BITDEPTH_32 + BUFFSIZE_512 + BUFFSIZE_1024 + BUFFSIZE_2048); 1024 setLastWorkingAudioDevName(); 1025 1026 // update config audio radio buttons if we're on that screen at the moment 1027 if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_AUDIO) 1028 showConfigScreen(); 1029 1030 updateWavRendererSettings(); 1031 setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32)); 1032 1033 // don't call stopVoices() in this routine 1034 for (int32_t i = 0; i < MAX_CHANNELS; i++) 1035 stopVoice(i); 1036 1037 stopAllScopes(); 1038 1039 // zero tick sample counter so that it will instantly initiate a tick 1040 audio.tickSampleCounterFrac = audio.tickSampleCounter = 0; 1041 1042 calcReplayerVars(audio.freq); 1043 1044 if (song.BPM == 0) 1045 song.BPM = 125; 1046 1047 setMixerBPM(song.BPM); // this is important 1048 1049 audio.resetSyncTickTimeFlag = true; 1050 1051 setWavRenderFrequency(audio.freq); 1052 setWavRenderBitDepth((config.specialFlags & BITDEPTH_32) ? 32 : 16); 1053 1054 return true; 1055 } 1056 1057 void closeAudio(void) 1058 { 1059 if (audio.dev > 0) 1060 { 1061 SDL_PauseAudioDevice(audio.dev, true); 1062 SDL_CloseAudioDevice(audio.dev); 1063 audio.dev = 0; 1064 } 1065 1066 freeAudioBuffers(); 1067 }