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 // --------------------------------
18 #include "mixer/ft2_mix.h"
19 #include "mixer/ft2_center_mix.h"
20 #include "mixer/ft2_silence_mix.h"
21 // --------------------------------
22
23 // hide POSIX warnings
24 #ifdef _MSC_VER
25 #pragma warning(disable: 4996)
26 #endif
27
28 #define INITIAL_DITHER_SEED 0x12345000
29
30 static int8_t pmpCountDiv, pmpChannels = 2;
31 static uint16_t smpBuffSize;
32 static uint32_t oldAudioFreq, tickTimeLen, tickTimeLenFrac, randSeed = INITIAL_DITHER_SEED;
33 static float fAudioNormalizeMul, fPanningTab[256+1];
34 static double dAudioNormalizeMul, dPrngStateL, dPrngStateR;
35 static voice_t voice[MAX_CHANNELS * 2];
36 static void (*sendAudSamplesFunc)(uint8_t *, uint32_t, uint8_t); // "send mixed samples" routines
37
38 // globalized
39 audio_t audio;
40 pattSyncData_t *pattSyncEntry;
41 chSyncData_t *chSyncEntry;
42 chSync_t chSync;
43 pattSync_t pattSync;
44 volatile bool pattQueueClearing, chQueueClearing;
45
resetCachedMixerVars(void)46 void resetCachedMixerVars(void)
47 {
48 channel_t *ch = channel;
49 for (int32_t i = 0; i < MAX_CHANNELS; i++, ch++)
50 ch->oldFinalPeriod = -1;
51
52 voice_t *v = voice;
53 for (int32_t i = 0; i < MAX_CHANNELS*2; i++, v++)
54 v->oldDelta = 0;
55 }
56
stopVoice(int32_t i)57 void stopVoice(int32_t i)
58 {
59 voice_t *v;
60
61 v = &voice[i];
62 memset(v, 0, sizeof (voice_t));
63 v->panning = 128;
64
65 // clear "fade out" voice too
66
67 v = &voice[MAX_CHANNELS + i];
68 memset(v, 0, sizeof (voice_t));
69 v->panning = 128;
70 }
71
setNewAudioSettings(void)72 bool setNewAudioSettings(void) // only call this from the main input/video thread
73 {
74 pauseAudio();
75
76 if (!setupAudio(CONFIG_HIDE_ERRORS))
77 {
78 // set back old known working settings
79
80 config.audioFreq = audio.lastWorkingAudioFreq;
81 config.specialFlags &= ~(BITDEPTH_16 + BITDEPTH_32 + BUFFSIZE_512 + BUFFSIZE_1024 + BUFFSIZE_2048);
82 config.specialFlags |= audio.lastWorkingAudioBits;
83
84 if (audio.lastWorkingAudioDeviceName != NULL)
85 {
86 if (audio.currOutputDevice != NULL)
87 {
88 free(audio.currOutputDevice);
89 audio.currOutputDevice = NULL;
90 }
91
92 audio.currOutputDevice = strdup(audio.lastWorkingAudioDeviceName);
93 }
94
95 // also update config audio radio buttons if we're on that screen at the moment
96 if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_IO_DEVICES)
97 setConfigIORadioButtonStates();
98
99 // if it didn't work to use the old settings again, then something is seriously wrong...
100 if (!setupAudio(CONFIG_HIDE_ERRORS))
101 okBox(0, "System message", "Couldn't find a working audio mode... You'll get no sound / replayer timer!");
102
103 resumeAudio();
104 return false;
105 }
106
107 resumeAudio();
108
109 setWavRenderFrequency(audio.freq);
110 setWavRenderBitDepth((config.specialFlags & BITDEPTH_32) ? 32 : 16);
111 return true;
112 }
113
114 // amp = 1..32, masterVol = 0..256
setAudioAmp(int16_t amp,int16_t masterVol,bool bitDepth32Flag)115 void setAudioAmp(int16_t amp, int16_t masterVol, bool bitDepth32Flag)
116 {
117 amp = CLAMP(amp, 1, 32);
118 masterVol = CLAMP(masterVol, 0, 256);
119
120 double dAmp = (amp * masterVol) / (32.0 * 256.0);
121 if (!bitDepth32Flag)
122 dAmp *= 32768.0;
123
124 dAudioNormalizeMul = dAmp;
125 fAudioNormalizeMul = (float)dAmp;
126 }
127
decreaseMasterVol(void)128 void decreaseMasterVol(void)
129 {
130 if (config.masterVol >= 16)
131 config.masterVol -= 16;
132 else
133 config.masterVol = 0;
134
135 setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
136
137 // if Config -> I/O Devices is open, update master volume scrollbar
138 if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_IO_DEVICES)
139 drawScrollBar(SB_MASTERVOL_SCROLL);
140 }
141
increaseMasterVol(void)142 void increaseMasterVol(void)
143 {
144 if (config.masterVol < (256-16))
145 config.masterVol += 16;
146 else
147 config.masterVol = 256;
148
149 setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
150
151 // if Config -> I/O Devices is open, update master volume scrollbar
152 if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_IO_DEVICES)
153 drawScrollBar(SB_MASTERVOL_SCROLL);
154 }
155
setNewAudioFreq(uint32_t freq)156 void setNewAudioFreq(uint32_t freq) // for song-to-WAV rendering
157 {
158 if (freq == 0)
159 return;
160
161 oldAudioFreq = audio.freq;
162 audio.freq = freq;
163
164 const bool mustRecalcTables = audio.freq != oldAudioFreq;
165 if (mustRecalcTables)
166 calcReplayerVars(audio.freq);
167 }
168
setBackOldAudioFreq(void)169 void setBackOldAudioFreq(void) // for song-to-WAV rendering
170 {
171 const bool mustRecalcTables = audio.freq != oldAudioFreq;
172
173 audio.freq = oldAudioFreq;
174
175 if (mustRecalcTables)
176 calcReplayerVars(audio.freq);
177 }
178
setMixerBPM(int32_t bpm)179 void setMixerBPM(int32_t bpm)
180 {
181 if (bpm < MIN_BPM || bpm > MAX_BPM)
182 return;
183
184 int32_t i = bpm - MIN_BPM;
185
186 audio.samplesPerTick64 = audio.samplesPerTick64Tab[i]; // fixed-point
187 audio.samplesPerTick = (audio.samplesPerTick64 + (1LL << 31)) >> 32; // rounded
188
189 // for audio/video sync timestamp
190 tickTimeLen = audio.tickTimeTab[i];
191 tickTimeLenFrac = audio.tickTimeFracTab[i];
192
193 // for calculating volume ramp length for tick-length ramps
194 audio.fRampTickMul = audio.fRampTickMulTab[i];
195 }
196
audioSetVolRamp(bool volRamp)197 void audioSetVolRamp(bool volRamp)
198 {
199 lockMixerCallback();
200 audio.volumeRampingFlag = volRamp;
201 unlockMixerCallback();
202 }
203
audioSetInterpolationType(uint8_t interpolationType)204 void audioSetInterpolationType(uint8_t interpolationType)
205 {
206 lockMixerCallback();
207 audio.interpolationType = interpolationType;
208 unlockMixerCallback();
209 }
210
calcPanningTable(void)211 void calcPanningTable(void)
212 {
213 // same formula as FT2's panning table (with 0.0f..1.0f range)
214 for (int32_t i = 0; i <= 256; i++)
215 fPanningTab[i] = sqrtf(i / 256.0f);
216 }
217
voiceUpdateVolumes(int32_t i,uint8_t status)218 static void voiceUpdateVolumes(int32_t i, uint8_t status)
219 {
220 voice_t *v = &voice[i];
221
222 const float fVolumeL = v->fVolume * fPanningTab[256-v->panning];
223 const float fVolumeR = v->fVolume * fPanningTab[ v->panning];
224
225 if (!audio.volumeRampingFlag)
226 {
227 // volume ramping is disabled
228 v->fVolumeL = fVolumeL;
229 v->fVolumeR = fVolumeR;
230 v->volumeRampLength = 0;
231 return;
232 }
233
234 v->fVolumeLTarget = fVolumeL;
235 v->fVolumeRTarget = fVolumeR;
236
237 if (status & IS_Trigger)
238 {
239 // sample is about to start, ramp out/in at the same time
240
241 // setup "fade out" voice (only if current voice volume > 0)
242 if (v->fVolumeL > 0.0f || v->fVolumeR > 0.0f)
243 {
244 voice_t *f = &voice[MAX_CHANNELS+i];
245
246 *f = *v; // copy voice
247
248 f->volumeRampLength = audio.quickVolRampSamples;
249
250 const float fVolumeLTarget = -f->fVolumeL;
251 const float fVolumeRTarget = -f->fVolumeR;
252
253 f->fVolumeLDelta = fVolumeLTarget * audio.fRampQuickVolMul;
254 f->fVolumeRDelta = fVolumeRTarget * audio.fRampQuickVolMul;
255
256 f->isFadeOutVoice = true;
257 }
258
259 // make current voice fade in from zero when it starts
260 v->fVolumeL = 0.0f;
261 v->fVolumeR = 0.0f;
262 }
263
264 // ramp volume changes
265
266 /* FT2 has two internal volume ramping lengths:
267 ** IS_QuickVol: 5ms
268 ** Normal: The duration of a tick (samplesPerTick)
269 */
270
271 // if destination volume and current volume is the same (and we have no sample trigger), don't do ramp
272 if (fVolumeL == v->fVolumeL && fVolumeR == v->fVolumeR && !(status & IS_Trigger))
273 {
274 // there is no volume change
275 v->volumeRampLength = 0;
276 }
277 else
278 {
279 const float fVolumeLTarget = fVolumeL - v->fVolumeL;
280 const float fVolumeRTarget = fVolumeR - v->fVolumeR;
281
282 if (status & IS_QuickVol)
283 {
284 v->fVolumeLDelta = fVolumeLTarget * audio.fRampQuickVolMul;
285 v->fVolumeRDelta = fVolumeRTarget * audio.fRampQuickVolMul;
286 v->volumeRampLength = audio.quickVolRampSamples;
287
288 }
289 else
290 {
291 v->fVolumeLDelta = fVolumeLTarget * audio.fRampTickMul;
292 v->fVolumeRDelta = fVolumeRTarget * audio.fRampTickMul;
293 v->volumeRampLength = audio.samplesPerTick;
294 }
295 }
296 }
297
voiceTrigger(int32_t ch,sample_t * s,int32_t position)298 static void voiceTrigger(int32_t ch, sample_t *s, int32_t position)
299 {
300 voice_t *v = &voice[ch];
301
302 int32_t length = s->length;
303 int32_t loopStart = s->loopStart;
304 int32_t loopLength = s->loopLength;
305 int32_t loopEnd = s->loopStart + s->loopLength;
306 uint8_t loopType = GET_LOOPTYPE(s->flags);
307 bool sample16Bit = !!(s->flags & SAMPLE_16BIT);
308
309 if (s->dataPtr == NULL || length < 1)
310 {
311 v->active = false; // shut down voice (illegal parameters)
312 return;
313 }
314
315 if (loopLength < 1) // disable loop if loopLength is below 1
316 loopType = 0;
317
318 if (sample16Bit)
319 {
320 v->base16 = (const int16_t *)s->dataPtr;
321 v->revBase16 = &v->base16[loopStart + loopEnd]; // for pingpong loops
322 v->leftEdgeTaps16 = s->leftEdgeTapSamples16 + SINC_LEFT_TAPS;
323 }
324 else
325 {
326 v->base8 = s->dataPtr;
327 v->revBase8 = &v->base8[loopStart + loopEnd]; // for pingpong loops
328 v->leftEdgeTaps8 = s->leftEdgeTapSamples8 + SINC_LEFT_TAPS;
329 }
330
331 v->hasLooped = false; // for sinc interpolation special case
332 v->samplingBackwards = false;
333 v->loopType = loopType;
334 v->sampleEnd = (loopType == LOOP_OFF) ? length : loopEnd;
335 v->loopStart = loopStart;
336 v->loopLength = loopLength;
337 v->position = position;
338 v->positionFrac = 0;
339
340 // if position overflows, shut down voice (f.ex. through 9xx command)
341 if (v->position >= v->sampleEnd)
342 {
343 v->active = false;
344 return;
345 }
346
347 v->mixFuncOffset = (sample16Bit * 9) + (audio.interpolationType * 3) + loopType;
348 v->active = true;
349 }
350
resetRampVolumes(void)351 void resetRampVolumes(void)
352 {
353 voice_t *v = voice;
354 for (int32_t i = 0; i < song.numChannels; i++, v++)
355 {
356 v->fVolumeL = v->fVolumeLTarget;
357 v->fVolumeR = v->fVolumeRTarget;
358 v->volumeRampLength = 0;
359 }
360 }
361
updateVoices(void)362 void updateVoices(void)
363 {
364 channel_t *ch = channel;
365 voice_t *v = voice;
366
367 for (int32_t i = 0; i < song.numChannels; i++, ch++, v++)
368 {
369 const uint8_t status = ch->tmpStatus = ch->status; // (tmpStatus is used for audio/video sync queue)
370 if (status == 0)
371 continue;
372
373 ch->status = 0;
374
375 if (status & IS_Vol)
376 {
377 v->fVolume = ch->fFinalVol;
378
379 const int32_t scopeVolume = (int32_t)((SCOPE_HEIGHT * ch->fFinalVol) + 0.5f); // rounded
380 v->scopeVolume = (uint8_t)scopeVolume;
381 }
382
383 if (status & IS_Pan)
384 v->panning = ch->finalPan;
385
386 if (status & (IS_Vol + IS_Pan))
387 voiceUpdateVolumes(i, status);
388
389 if (status & IS_Period)
390 {
391 // use cached values when possible
392 if (ch->finalPeriod != ch->oldFinalPeriod)
393 {
394 ch->oldFinalPeriod = ch->finalPeriod;
395
396 if (ch->finalPeriod == 0) // in FT2, period 0 -> delta 0
397 {
398 v->scopeDelta = 0;
399 v->oldDelta = 0;
400 v->fSincLUT = fKaiserSinc;
401 }
402 else
403 {
404 const double dHz = dPeriod2Hz(ch->finalPeriod);
405 const uintCPUWord_t delta = v->oldDelta = (intCPUWord_t)((dHz * audio.dHz2MixDeltaMul) + 0.5); // Hz -> fixed-point delta (rounded)
406
407 // decide which polyphase sinc LUT to use according to resampling ratio
408 if (delta <= (uintCPUWord_t)(1.1875 * MIXER_FRAC_SCALE))
409 v->fSincLUT = fKaiserSinc;
410 else if (delta <= (uintCPUWord_t)(1.5 * MIXER_FRAC_SCALE))
411 v->fSincLUT = fDownSample1;
412 else
413 v->fSincLUT = fDownSample2;
414
415 // set scope delta
416 const double dHz2ScopeDeltaMul = SCOPE_FRAC_SCALE / (double)SCOPE_HZ;
417 v->scopeDelta = (intCPUWord_t)((dHz * dHz2ScopeDeltaMul) + 0.5); // Hz -> fixed-point delta (rounded)
418 }
419 }
420
421 v->delta = v->oldDelta;
422 }
423
424 if (status & IS_Trigger)
425 voiceTrigger(i, ch->smpPtr, ch->smpStartPos);
426 }
427 }
428
resetAudioDither(void)429 void resetAudioDither(void)
430 {
431 randSeed = INITIAL_DITHER_SEED;
432 dPrngStateL = 0.0;
433 dPrngStateR = 0.0;
434 }
435
random32(void)436 static inline int32_t random32(void)
437 {
438 // LCG 32-bit random
439 randSeed *= 134775813;
440 randSeed++;
441
442 return (int32_t)randSeed;
443 }
444
sendSamples16BitDitherStereo(uint8_t * stream,uint32_t sampleBlockLength,uint8_t numAudioChannels)445 static void sendSamples16BitDitherStereo(uint8_t *stream, uint32_t sampleBlockLength, uint8_t numAudioChannels)
446 {
447 int32_t out32;
448 double dOut, dPrng;
449
450 int16_t *streamPointer16 = (int16_t *)stream;
451 for (uint32_t i = 0; i < sampleBlockLength; i++)
452 {
453 // left channel - 1-bit triangular dithering
454 dPrng = random32() * (0.5 / INT32_MAX); // -0.5 .. 0.5
455 dOut = (double)audio.fMixBufferL[i] * dAudioNormalizeMul;
456 dOut = (dOut + dPrng) - dPrngStateL;
457 dPrngStateL = dPrng;
458 out32 = (int32_t)dOut;
459 CLAMP16(out32);
460 *streamPointer16++ = (int16_t)out32;
461
462 // right channel - 1-bit triangular dithering
463 dPrng = random32() * (0.5 / INT32_MAX); // -0.5 .. 0.5
464 dOut = (double)audio.fMixBufferR[i] * dAudioNormalizeMul;
465 dOut = (dOut + dPrng) - dPrngStateR;
466 dPrngStateR = dPrng;
467 out32 = (int32_t)dOut;
468 CLAMP16(out32);
469 *streamPointer16++ = (int16_t)out32;
470
471 // clear what we read from the mixing buffer
472 audio.fMixBufferL[i] = 0.0f;
473 audio.fMixBufferR[i] = 0.0f;
474 }
475
476 (void)numAudioChannels;
477 }
478
sendSamples16BitDitherMultiChan(uint8_t * stream,uint32_t sampleBlockLength,uint8_t numAudioChannels)479 static void sendSamples16BitDitherMultiChan(uint8_t *stream, uint32_t sampleBlockLength, uint8_t numAudioChannels)
480 {
481 int32_t out32;
482 double dOut, dPrng;
483
484 int16_t *streamPointer16 = (int16_t *)stream;
485 for (uint32_t i = 0; i < sampleBlockLength; i++)
486 {
487 // left channel - 1-bit triangular dithering
488 dPrng = random32() * (0.5 / INT32_MAX); // -0.5 .. 0.5
489 dOut = (double)audio.fMixBufferL[i] * dAudioNormalizeMul;
490 dOut = (dOut + dPrng) - dPrngStateL;
491 dPrngStateL = dPrng;
492 out32 = (int32_t)dOut;
493 CLAMP16(out32);
494 *streamPointer16++ = (int16_t)out32;
495
496 // right channel - 1-bit triangular dithering
497 dPrng = random32() * (0.5 / INT32_MAX); // -0.5 .. 0.5
498 dOut = (double)audio.fMixBufferR[i] * dAudioNormalizeMul;
499 dOut = (dOut + dPrng) - dPrngStateR;
500 dPrngStateR = dPrng;
501 out32 = (int32_t)dOut;
502 CLAMP16(out32);
503 *streamPointer16++ = (int16_t)out32;
504
505 // clear what we read from the mixing buffer
506 audio.fMixBufferL[i] = 0.0f;
507 audio.fMixBufferR[i] = 0.0f;
508
509 // send zeroes to the rest of the channels
510 for (uint32_t j = 2; j < numAudioChannels; j++)
511 *streamPointer16++ = 0;
512 }
513 }
514
sendSamples32BitStereo(uint8_t * stream,uint32_t sampleBlockLength,uint8_t numAudioChannels)515 static void sendSamples32BitStereo(uint8_t *stream, uint32_t sampleBlockLength, uint8_t numAudioChannels)
516 {
517 float fOut, *fStreamPointer32 = (float *)stream;
518 for (uint32_t i = 0; i < sampleBlockLength; i++)
519 {
520 // left channel
521 fOut = audio.fMixBufferL[i] * fAudioNormalizeMul;
522 fOut = CLAMP(fOut, -1.0f, 1.0f);
523 *fStreamPointer32++ = fOut;
524
525 // right channel
526 fOut = audio.fMixBufferR[i] * fAudioNormalizeMul;
527 fOut = CLAMP(fOut, -1.0f, 1.0f);
528 *fStreamPointer32++ = fOut;
529
530 // clear what we read from the mixing buffer
531 audio.fMixBufferL[i] = 0.0f;
532 audio.fMixBufferR[i] = 0.0f;
533 }
534
535 (void)numAudioChannels;
536 }
537
sendSamples32BitMultiChan(uint8_t * stream,uint32_t sampleBlockLength,uint8_t numAudioChannels)538 static void sendSamples32BitMultiChan(uint8_t *stream, uint32_t sampleBlockLength, uint8_t numAudioChannels)
539 {
540 float fOut, *fStreamPointer32 = (float *)stream;
541 for (uint32_t i = 0; i < sampleBlockLength; i++)
542 {
543 // left channel
544 fOut = audio.fMixBufferL[i] * fAudioNormalizeMul;
545 fOut = CLAMP(fOut, -1.0f, 1.0f);
546 *fStreamPointer32++ = fOut;
547
548 // right channel
549 fOut = audio.fMixBufferR[i] * fAudioNormalizeMul;
550 fOut = CLAMP(fOut, -1.0f, 1.0f);
551 *fStreamPointer32++ = fOut;
552
553 // clear what we read from the mixing buffer
554 audio.fMixBufferL[i] = 0.0f;
555 audio.fMixBufferR[i] = 0.0f;
556
557 // send zeroes to the rest of the channels
558 for (uint32_t j = 2; j < numAudioChannels; j++)
559 *fStreamPointer32++ = 0.0f;
560 }
561 }
562
doChannelMixing(int32_t bufferPosition,int32_t samplesToMix)563 static void doChannelMixing(int32_t bufferPosition, int32_t samplesToMix)
564 {
565 voice_t *v = voice; // normal voices
566 voice_t *r = &voice[MAX_CHANNELS]; // volume ramp fadeout-voices
567
568 for (int32_t i = 0; i < song.numChannels; i++, v++, r++)
569 {
570 if (v->active)
571 {
572 bool centerMixFlag;
573
574 const bool volRampFlag = (v->volumeRampLength > 0);
575 if (volRampFlag)
576 {
577 centerMixFlag = (v->fVolumeLTarget == v->fVolumeRTarget) && (v->fVolumeLDelta == v->fVolumeRDelta);
578 }
579 else // no volume ramping active
580 {
581 if (v->fVolumeL == 0.0f && v->fVolumeR == 0.0f)
582 {
583 silenceMixRoutine(v, samplesToMix);
584 continue;
585 }
586
587 centerMixFlag = (v->fVolumeL == v->fVolumeR);
588 }
589
590 mixFuncTab[((int32_t)centerMixFlag * 36) + ((int32_t)volRampFlag * 18) + v->mixFuncOffset](v, bufferPosition, samplesToMix);
591 }
592
593 if (r->active) // volume ramp fadeout-voice
594 {
595 const bool centerMixFlag = (r->fVolumeLTarget == r->fVolumeRTarget) && (r->fVolumeLDelta == r->fVolumeRDelta);
596 mixFuncTab[((int32_t)centerMixFlag * 36) + 18 + r->mixFuncOffset](r, bufferPosition, samplesToMix);
597 }
598 }
599 }
600
601 // used for song-to-WAV renderer
mixReplayerTickToBuffer(uint32_t samplesToMix,uint8_t * stream,uint8_t bitDepth)602 void mixReplayerTickToBuffer(uint32_t samplesToMix, uint8_t *stream, uint8_t bitDepth)
603 {
604 assert(samplesToMix <= MAX_WAV_RENDER_SAMPLES_PER_TICK);
605 doChannelMixing(0, samplesToMix);
606
607 // normalize mix buffer and send to audio stream
608 if (bitDepth == 16)
609 sendSamples16BitDitherStereo(stream, samplesToMix, 2);
610 else
611 sendSamples32BitStereo(stream, samplesToMix, 2);
612 }
613
pattQueueReadSize(void)614 int32_t pattQueueReadSize(void)
615 {
616 while (pattQueueClearing);
617
618 if (pattSync.writePos > pattSync.readPos)
619 return pattSync.writePos - pattSync.readPos;
620 else if (pattSync.writePos < pattSync.readPos)
621 return pattSync.writePos - pattSync.readPos + SYNC_QUEUE_LEN + 1;
622 else
623 return 0;
624 }
625
pattQueueWriteSize(void)626 int32_t pattQueueWriteSize(void)
627 {
628 int32_t size;
629
630 if (pattSync.writePos > pattSync.readPos)
631 {
632 size = pattSync.readPos - pattSync.writePos + SYNC_QUEUE_LEN;
633 }
634 else if (pattSync.writePos < pattSync.readPos)
635 {
636 pattQueueClearing = true;
637
638 /* Buffer is full, reset the read/write pos. This is actually really nasty since
639 ** read/write are two different threads, but because of timestamp validation it
640 ** shouldn't be that dangerous.
641 ** It will also create a small visual stutter while the buffer is getting filled,
642 ** though that is barely noticable on normal buffer sizes, and it takes a minute
643 ** or two at max BPM between each time (when queue size is default, 4095)
644 */
645 pattSync.data[0].timestamp = 0;
646 pattSync.readPos = 0;
647 pattSync.writePos = 0;
648
649 size = SYNC_QUEUE_LEN;
650
651 pattQueueClearing = false;
652 }
653 else
654 {
655 size = SYNC_QUEUE_LEN;
656 }
657
658 return size;
659 }
660
pattQueuePush(pattSyncData_t t)661 bool pattQueuePush(pattSyncData_t t)
662 {
663 if (!pattQueueWriteSize())
664 return false;
665
666 assert(pattSync.writePos <= SYNC_QUEUE_LEN);
667 pattSync.data[pattSync.writePos] = t;
668 pattSync.writePos = (pattSync.writePos + 1) & SYNC_QUEUE_LEN;
669
670 return true;
671 }
672
pattQueuePop(void)673 bool pattQueuePop(void)
674 {
675 if (!pattQueueReadSize())
676 return false;
677
678 pattSync.readPos = (pattSync.readPos + 1) & SYNC_QUEUE_LEN;
679 assert(pattSync.readPos <= SYNC_QUEUE_LEN);
680
681 return true;
682 }
683
pattQueuePeek(void)684 pattSyncData_t *pattQueuePeek(void)
685 {
686 if (!pattQueueReadSize())
687 return NULL;
688
689 assert(pattSync.readPos <= SYNC_QUEUE_LEN);
690 return &pattSync.data[pattSync.readPos];
691 }
692
getPattQueueTimestamp(void)693 uint64_t getPattQueueTimestamp(void)
694 {
695 if (!pattQueueReadSize())
696 return 0;
697
698 assert(pattSync.readPos <= SYNC_QUEUE_LEN);
699 return pattSync.data[pattSync.readPos].timestamp;
700 }
701
chQueueReadSize(void)702 int32_t chQueueReadSize(void)
703 {
704 while (chQueueClearing);
705
706 if (chSync.writePos > chSync.readPos)
707 return chSync.writePos - chSync.readPos;
708 else if (chSync.writePos < chSync.readPos)
709 return chSync.writePos - chSync.readPos + SYNC_QUEUE_LEN + 1;
710 else
711 return 0;
712 }
713
chQueueWriteSize(void)714 int32_t chQueueWriteSize(void)
715 {
716 int32_t size;
717
718 if (chSync.writePos > chSync.readPos)
719 {
720 size = chSync.readPos - chSync.writePos + SYNC_QUEUE_LEN;
721 }
722 else if (chSync.writePos < chSync.readPos)
723 {
724 chQueueClearing = true;
725
726 /* Buffer is full, reset the read/write pos. This is actually really nasty since
727 ** read/write are two different threads, but because of timestamp validation it
728 ** shouldn't be that dangerous.
729 ** It will also create a small visual stutter while the buffer is getting filled,
730 ** though that is barely noticable on normal buffer sizes, and it takes several
731 ** minutes between each time (when queue size is default, 16384)
732 */
733 chSync.data[0].timestamp = 0;
734 chSync.readPos = 0;
735 chSync.writePos = 0;
736
737 size = SYNC_QUEUE_LEN;
738
739 chQueueClearing = false;
740 }
741 else
742 {
743 size = SYNC_QUEUE_LEN;
744 }
745
746 return size;
747 }
748
chQueuePush(chSyncData_t t)749 bool chQueuePush(chSyncData_t t)
750 {
751 if (!chQueueWriteSize())
752 return false;
753
754 assert(chSync.writePos <= SYNC_QUEUE_LEN);
755 chSync.data[chSync.writePos] = t;
756 chSync.writePos = (chSync.writePos + 1) & SYNC_QUEUE_LEN;
757
758 return true;
759 }
760
chQueuePop(void)761 bool chQueuePop(void)
762 {
763 if (!chQueueReadSize())
764 return false;
765
766 chSync.readPos = (chSync.readPos + 1) & SYNC_QUEUE_LEN;
767 assert(chSync.readPos <= SYNC_QUEUE_LEN);
768
769 return true;
770 }
771
chQueuePeek(void)772 chSyncData_t *chQueuePeek(void)
773 {
774 if (!chQueueReadSize())
775 return NULL;
776
777 assert(chSync.readPos <= SYNC_QUEUE_LEN);
778 return &chSync.data[chSync.readPos];
779 }
780
getChQueueTimestamp(void)781 uint64_t getChQueueTimestamp(void)
782 {
783 if (!chQueueReadSize())
784 return 0;
785
786 assert(chSync.readPos <= SYNC_QUEUE_LEN);
787 return chSync.data[chSync.readPos].timestamp;
788 }
789
lockAudio(void)790 void lockAudio(void)
791 {
792 if (audio.dev != 0)
793 SDL_LockAudioDevice(audio.dev);
794
795 audio.locked = true;
796 }
797
unlockAudio(void)798 void unlockAudio(void)
799 {
800 if (audio.dev != 0)
801 SDL_UnlockAudioDevice(audio.dev);
802
803 audio.locked = false;
804 }
805
resetSyncQueues(void)806 void resetSyncQueues(void)
807 {
808 pattSync.data[0].timestamp = 0;
809 pattSync.readPos = 0;
810 pattSync.writePos = 0;
811
812 chSync.data[0].timestamp = 0;
813 chSync.writePos = 0;
814 chSync.readPos = 0;
815 }
816
lockMixerCallback(void)817 void lockMixerCallback(void) // lock audio + clear voices/scopes (for short operations)
818 {
819 if (!audio.locked)
820 lockAudio();
821
822 audio.resetSyncTickTimeFlag = true;
823
824 stopVoices(); // VERY important! prevents potential crashes by purging pointers
825
826 // scopes, mixer and replayer are guaranteed to not be active at this point
827
828 resetSyncQueues();
829 }
830
unlockMixerCallback(void)831 void unlockMixerCallback(void)
832 {
833 stopVoices(); // VERY important! prevents potential crashes by purging pointers
834
835 if (audio.locked)
836 unlockAudio();
837 }
838
pauseAudio(void)839 void pauseAudio(void) // lock audio + clear voices/scopes + render silence (for long operations)
840 {
841 if (audioPaused)
842 {
843 stopVoices(); // VERY important! prevents potential crashes by purging pointers
844 return;
845 }
846
847 if (audio.dev > 0)
848 SDL_PauseAudioDevice(audio.dev, true);
849
850 audio.resetSyncTickTimeFlag = true;
851
852 stopVoices(); // VERY important! prevents potential crashes by purging pointers
853
854 // scopes, mixer and replayer are guaranteed to not be active at this point
855
856 resetSyncQueues();
857 audioPaused = true;
858 }
859
resumeAudio(void)860 void resumeAudio(void) // unlock audio
861 {
862 if (!audioPaused)
863 return;
864
865 if (audio.dev > 0)
866 SDL_PauseAudioDevice(audio.dev, false);
867
868 audioPaused = false;
869 }
870
fillVisualsSyncBuffer(void)871 static void fillVisualsSyncBuffer(void)
872 {
873 pattSyncData_t pattSyncData;
874 chSyncData_t chSyncData;
875
876 if (audio.resetSyncTickTimeFlag)
877 {
878 audio.resetSyncTickTimeFlag = false;
879
880 audio.tickTime64 = SDL_GetPerformanceCounter() + audio.audLatencyPerfValInt;
881 audio.tickTime64Frac = audio.audLatencyPerfValFrac;
882 }
883
884 if (songPlaying)
885 {
886 // push pattern variables to sync queue
887 pattSyncData.tick = song.curReplayerTick;
888 pattSyncData.row = song.curReplayerRow;
889 pattSyncData.pattNum = song.curReplayerPattNum;
890 pattSyncData.songPos = song.curReplayerSongPos;
891 pattSyncData.BPM = song.BPM;
892 pattSyncData.speed = (uint8_t)song.speed;
893 pattSyncData.globalVolume = (uint8_t)song.globalVolume;
894 pattSyncData.timestamp = audio.tickTime64;
895 pattQueuePush(pattSyncData);
896 }
897
898 // push channel variables to sync queue
899
900 syncedChannel_t *c = chSyncData.channels;
901 channel_t *s = channel;
902 voice_t *v = voice;
903
904 for (int32_t i = 0; i < song.numChannels; i++, c++, s++, v++)
905 {
906 c->scopeVolume = v->scopeVolume;
907 c->scopeDelta = v->scopeDelta;
908 c->instrNum = s->instrNum;
909 c->smpNum = s->smpNum;
910 c->status = s->tmpStatus;
911 c->smpStartPos = s->smpStartPos;
912
913 c->pianoNoteNum = 255; // no piano key
914 if (songPlaying && (c->status & IS_Period) && s->envSustainActive)
915 {
916 const int32_t note = getPianoKey(s->finalPeriod, s->finetune, s->relativeNote);
917 if (note >= 0 && note <= 95)
918 c->pianoNoteNum = (uint8_t)note;
919 }
920 }
921
922 chSyncData.timestamp = audio.tickTime64;
923 chQueuePush(chSyncData);
924
925 audio.tickTime64 += tickTimeLen;
926 audio.tickTime64Frac += tickTimeLenFrac;
927 if (audio.tickTime64Frac > UINT32_MAX)
928 {
929 audio.tickTime64Frac &= UINT32_MAX;
930 audio.tickTime64++;
931 }
932 }
933
audioCallback(void * userdata,Uint8 * stream,int len)934 static void SDLCALL audioCallback(void *userdata, Uint8 *stream, int len)
935 {
936 if (editor.wavIsRendering)
937 return;
938
939 len /= pmpCountDiv; // bytes -> samples
940 if (len <= 0)
941 return;
942
943 assert(len <= MAX_WAV_RENDER_SAMPLES_PER_TICK);
944
945 int32_t bufferPosition = 0;
946
947 int32_t samplesLeft = len;
948 while (samplesLeft > 0)
949 {
950 if (audio.tickSampleCounter64 <= 0) // new replayer tick
951 {
952 replayerBusy = true;
953
954 if (audio.volumeRampingFlag)
955 resetRampVolumes();
956
957 tickReplayer();
958 updateVoices();
959 fillVisualsSyncBuffer();
960
961 audio.tickSampleCounter64 += audio.samplesPerTick64;
962
963 replayerBusy = false;
964 }
965
966 const int32_t remainingTick = (audio.tickSampleCounter64 + UINT32_MAX) >> 32; // ceil (rounded upwards)
967
968 int32_t samplesToMix = samplesLeft;
969 if (samplesToMix > remainingTick)
970 samplesToMix = remainingTick;
971
972 doChannelMixing(bufferPosition, samplesToMix);
973
974 bufferPosition += samplesToMix;
975 samplesLeft -= samplesToMix;
976 audio.tickSampleCounter64 -= (int64_t)samplesToMix << 32;
977 }
978
979 // normalize mix buffer and send to audio stream
980 sendAudSamplesFunc(stream, len, pmpChannels);
981
982 (void)userdata;
983 }
984
setupAudioBuffers(void)985 static bool setupAudioBuffers(void)
986 {
987 const uint32_t sampleSize = sizeof (float);
988
989 audio.fMixBufferLUnaligned = (float *)MALLOC_PAD(MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize, 256);
990 audio.fMixBufferRUnaligned = (float *)MALLOC_PAD(MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize, 256);
991
992 if (audio.fMixBufferLUnaligned == NULL || audio.fMixBufferRUnaligned == NULL)
993 return false;
994
995 // make aligned main pointers
996 audio.fMixBufferL = (float *)ALIGN_PTR(audio.fMixBufferLUnaligned, 256);
997 audio.fMixBufferR = (float *)ALIGN_PTR(audio.fMixBufferRUnaligned, 256);
998
999 // clear buffers
1000 memset(audio.fMixBufferL, 0, MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize);
1001 memset(audio.fMixBufferR, 0, MAX_WAV_RENDER_SAMPLES_PER_TICK * sampleSize);
1002
1003 return true;
1004 }
1005
freeAudioBuffers(void)1006 static void freeAudioBuffers(void)
1007 {
1008 if (audio.fMixBufferLUnaligned != NULL)
1009 {
1010 free(audio.fMixBufferLUnaligned);
1011 audio.fMixBufferLUnaligned = NULL;
1012 }
1013
1014 if (audio.fMixBufferRUnaligned != NULL)
1015 {
1016 free(audio.fMixBufferRUnaligned);
1017 audio.fMixBufferRUnaligned = NULL;
1018 }
1019
1020 audio.fMixBufferL = NULL;
1021 audio.fMixBufferR = NULL;
1022 }
1023
updateSendAudSamplesRoutine(bool lockMixer)1024 void updateSendAudSamplesRoutine(bool lockMixer)
1025 {
1026 if (lockMixer)
1027 lockMixerCallback();
1028
1029 if (config.specialFlags & BITDEPTH_16)
1030 {
1031 if (pmpChannels > 2)
1032 sendAudSamplesFunc = sendSamples16BitDitherMultiChan;
1033 else
1034 sendAudSamplesFunc = sendSamples16BitDitherStereo;
1035 }
1036 else
1037 {
1038 if (pmpChannels > 2)
1039 sendAudSamplesFunc = sendSamples32BitMultiChan;
1040 else
1041 sendAudSamplesFunc = sendSamples32BitStereo;
1042 }
1043
1044 if (lockMixer)
1045 unlockMixerCallback();
1046 }
1047
calcAudioLatencyVars(int32_t audioBufferSize,int32_t audioFreq)1048 static void calcAudioLatencyVars(int32_t audioBufferSize, int32_t audioFreq)
1049 {
1050 double dInt;
1051
1052 if (audioFreq == 0)
1053 return;
1054
1055 const double dAudioLatencySecs = audioBufferSize / (double)audioFreq;
1056
1057 double dFrac = modf(dAudioLatencySecs * editor.dPerfFreq, &dInt);
1058
1059 // integer part
1060 audio.audLatencyPerfValInt = (int32_t)dInt;
1061
1062 // fractional part (scaled to 0..2^32-1)
1063 dFrac *= UINT32_MAX+1.0;
1064 audio.audLatencyPerfValFrac = (uint32_t)dFrac;
1065
1066 audio.dAudioLatencyMs = dAudioLatencySecs * 1000.0;
1067 }
1068
setLastWorkingAudioDevName(void)1069 static void setLastWorkingAudioDevName(void)
1070 {
1071 if (audio.lastWorkingAudioDeviceName != NULL)
1072 {
1073 free(audio.lastWorkingAudioDeviceName);
1074 audio.lastWorkingAudioDeviceName = NULL;
1075 }
1076
1077 if (audio.currOutputDevice != NULL)
1078 audio.lastWorkingAudioDeviceName = strdup(audio.currOutputDevice);
1079 }
1080
setupAudio(bool showErrorMsg)1081 bool setupAudio(bool showErrorMsg)
1082 {
1083 SDL_AudioSpec want, have;
1084
1085 closeAudio();
1086
1087 if (config.audioFreq < MIN_AUDIO_FREQ || config.audioFreq > MAX_AUDIO_FREQ)
1088 config.audioFreq = DEFAULT_AUDIO_FREQ;
1089
1090 // get audio buffer size from config special flags
1091
1092 uint16_t configAudioBufSize = 1024;
1093 if (config.specialFlags & BUFFSIZE_512)
1094 configAudioBufSize = 512;
1095 else if (config.specialFlags & BUFFSIZE_2048)
1096 configAudioBufSize = 2048;
1097
1098 audio.wantFreq = config.audioFreq;
1099 audio.wantSamples = configAudioBufSize;
1100 audio.wantChannels = 2;
1101
1102 // set up audio device
1103 memset(&want, 0, sizeof (want));
1104
1105 // these three may change after opening a device, but our mixer is dealing with it
1106 want.freq = config.audioFreq;
1107 want.format = (config.specialFlags & BITDEPTH_32) ? AUDIO_F32 : AUDIO_S16;
1108 want.channels = 2;
1109 // -------------------------------------------------------------------------------
1110 want.callback = audioCallback;
1111 want.samples = configAudioBufSize;
1112
1113 audio.dev = SDL_OpenAudioDevice(audio.currOutputDevice, 0, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE); // prevent SDL2 from resampling
1114 if (audio.dev == 0)
1115 {
1116 if (showErrorMsg)
1117 showErrorMsgBox("Couldn't open audio device:\n\"%s\"\n\nDo you have any audio device enabled and plugged in?", SDL_GetError());
1118
1119 return false;
1120 }
1121
1122 // test if the received audio format is compatible
1123 if (have.format != AUDIO_S16 && have.format != AUDIO_F32)
1124 {
1125 if (showErrorMsg)
1126 showErrorMsgBox("Couldn't open audio device:\nThe program doesn't support an SDL_AudioFormat of '%d' (not 16-bit or 32-bit float).",
1127 (uint32_t)have.format);
1128
1129 closeAudio();
1130 return false;
1131 }
1132
1133 // test if the received audio rate is compatible
1134
1135 #if CPU_64BIT
1136 if (have.freq != 44100 && have.freq != 48000 && have.freq != 96000 && have.freq != 192000)
1137 #else
1138 if (have.freq != 44100 && have.freq != 48000)
1139 #endif
1140 {
1141 if (showErrorMsg)
1142 showErrorMsgBox("Couldn't open audio device:\nThis program doesn't support an audio output rate of %dHz. Sorry!", have.freq);
1143
1144 closeAudio();
1145 return false;
1146 }
1147
1148 if (!setupAudioBuffers())
1149 {
1150 if (showErrorMsg)
1151 showErrorMsgBox("Not enough memory!");
1152
1153 closeAudio();
1154 return false;
1155 }
1156
1157 // set new bit depth flag
1158
1159 int8_t newBitDepth = 16;
1160 config.specialFlags &= ~BITDEPTH_32;
1161 config.specialFlags |= BITDEPTH_16;
1162
1163 if (have.format == AUDIO_F32)
1164 {
1165 newBitDepth = 24;
1166 config.specialFlags &= ~BITDEPTH_16;
1167 config.specialFlags |= BITDEPTH_32;
1168 }
1169
1170 audio.haveFreq = have.freq;
1171 audio.haveSamples = have.samples;
1172 audio.haveChannels = have.channels;
1173
1174 // set a few variables
1175
1176 config.audioFreq = have.freq;
1177 audio.freq = have.freq;
1178 smpBuffSize = have.samples;
1179
1180 calcAudioLatencyVars(have.samples, have.freq);
1181
1182 pmpChannels = have.channels;
1183 pmpCountDiv = pmpChannels * ((newBitDepth == 16) ? sizeof (int16_t) : sizeof (float));
1184
1185 // make a copy of the new known working audio settings
1186
1187 audio.lastWorkingAudioFreq = config.audioFreq;
1188 audio.lastWorkingAudioBits = config.specialFlags & (BITDEPTH_16 + BITDEPTH_32 + BUFFSIZE_512 + BUFFSIZE_1024 + BUFFSIZE_2048);
1189 setLastWorkingAudioDevName();
1190
1191 // update config audio radio buttons if we're on that screen at the moment
1192 if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_IO_DEVICES)
1193 showConfigScreen();
1194
1195 updateWavRendererSettings();
1196 setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
1197
1198 // don't call stopVoices() in this routine
1199 for (int32_t i = 0; i < MAX_CHANNELS; i++)
1200 stopVoice(i);
1201
1202 stopAllScopes();
1203
1204 audio.tickSampleCounter64 = 0; // zero tick sample counter so that it will instantly initiate a tick
1205
1206 calcReplayerVars(audio.freq);
1207
1208 if (song.BPM == 0)
1209 song.BPM = 125;
1210
1211 setMixerBPM(song.BPM); // this is important
1212
1213 updateSendAudSamplesRoutine(false);
1214 audio.resetSyncTickTimeFlag = true;
1215
1216 setWavRenderFrequency(audio.freq);
1217 setWavRenderBitDepth((config.specialFlags & BITDEPTH_32) ? 32 : 16);
1218
1219 return true;
1220 }
1221
closeAudio(void)1222 void closeAudio(void)
1223 {
1224 if (audio.dev > 0)
1225 {
1226 SDL_PauseAudioDevice(audio.dev, true);
1227 SDL_CloseAudioDevice(audio.dev);
1228 audio.dev = 0;
1229 }
1230
1231 freeAudioBuffers();
1232 }
1233