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 <stdint.h>
7 #include <stdio.h>
8 #include <math.h>
9 #include "ft2_header.h"
10 #include "ft2_config.h"
11 #include "ft2_gui.h"
12 #include "ft2_video.h"
13 #include "ft2_pattern_ed.h"
14 #include "ft2_sample_ed.h"
15 #include "ft2_inst_ed.h"
16 #include "ft2_diskop.h"
17 #include "ft2_midi.h"
18 #include "scopes/ft2_scopes.h"
19 #include "ft2_mouse.h"
20 #include "ft2_sample_loader.h"
21 #include "ft2_tables.h"
22 #include "ft2_structs.h"
23 #include "mixer/ft2_windowed_sinc.h"
24 
25 static double dLogTab[4*12*16], dExp2MulTab[32];
26 static bool bxxOverflow;
27 static note_t nilPatternLine[MAX_CHANNELS];
28 
29 typedef void (*volColumnEfxRoutine)(channel_t *ch);
30 typedef void (*volColumnEfxRoutine2)(channel_t *ch, uint8_t *volColumnData);
31 typedef void (*efxRoutine)(channel_t *ch, uint8_t param);
32 
33 // globally accessed
34 int8_t playMode = 0;
35 bool songPlaying = false, audioPaused = false, musicPaused = false;
36 volatile bool replayerBusy = false;
37 const uint16_t *note2Period = NULL;
38 int16_t patternNumRows[MAX_PATTERNS];
39 channel_t channel[MAX_CHANNELS];
40 song_t song;
41 instr_t *instr[128+4];
42 note_t *pattern[MAX_PATTERNS];
43 // ----------------------------------
44 
fixString(char * str,int32_t lastChrPos)45 void fixString(char *str, int32_t lastChrPos) // removes leading spaces and 0x1A chars
46 {
47 	for (int32_t i = lastChrPos; i >= 0; i--)
48 	{
49 		if (str[i] == ' ' || str[i] == 0x1A)
50 			str[i] = '\0';
51 		else if (str[i] != '\0')
52 			break;
53 	}
54 	str[lastChrPos+1] = '\0';
55 }
56 
fixSongName(void)57 void fixSongName(void)
58 {
59 	fixString(song.name, 19);
60 }
61 
fixInstrAndSampleNames(int16_t insNum)62 void fixInstrAndSampleNames(int16_t insNum)
63 {
64 	fixString(song.instrName[insNum], 21);
65 	if (instr[insNum] != NULL)
66 	{
67 		sample_t *s = instr[insNum]->smp;
68 		for (int32_t i = 0; i < MAX_SMP_PER_INST; i++, s++)
69 			fixString(s->name, 21);
70 	}
71 }
72 
resetChannels(void)73 void resetChannels(void)
74 {
75 	const bool audioWasntLocked = !audio.locked;
76 	if (audioWasntLocked)
77 		lockAudio();
78 
79 	memset(channel, 0, sizeof (channel));
80 
81 	channel_t *ch = channel;
82 	for (int32_t i = 0; i < MAX_CHANNELS; i++, ch++)
83 	{
84 		ch->instrPtr = instr[0];
85 		ch->status = IS_Vol;
86 		ch->oldPan = 128;
87 		ch->outPan = 128;
88 		ch->finalPan = 128;
89 
90 		ch->channelOff = !editor.chnMode[i]; // set channel mute flag from global mute flag
91 	}
92 
93 	if (audioWasntLocked)
94 		unlockAudio();
95 }
96 
setSongModifiedFlag(void)97 void setSongModifiedFlag(void)
98 {
99 	song.isModified = true;
100 	editor.updateWindowTitle = true;
101 }
102 
removeSongModifiedFlag(void)103 void removeSongModifiedFlag(void)
104 {
105 	song.isModified = false;
106 	editor.updateWindowTitle = true;
107 }
108 
109 // used on external sample load and during sample loading (on some module formats)
tuneSample(sample_t * s,const int32_t midCFreq,bool linearPeriodsFlag)110 void tuneSample(sample_t *s, const int32_t midCFreq, bool linearPeriodsFlag)
111 {
112 	#define MIN_PERIOD (0)
113 	#define MAX_PERIOD (((10*12*16)-1)-1) /* -1 (because of bugged amigaPeriods table values) */
114 
115 	double (*dGetHzFromPeriod)(int32_t) = linearPeriodsFlag ? dLinearPeriod2Hz : dAmigaPeriod2Hz;
116 	const uint16_t *periodTab = linearPeriodsFlag ? linearPeriods : amigaPeriods;
117 
118 	if (midCFreq <= 0 || periodTab == NULL)
119 	{
120 		s->finetune = s->relativeNote = 0;
121 		return;
122 	}
123 
124 	// handle frequency boundaries first...
125 
126 	if (midCFreq <= (int32_t)dGetHzFromPeriod(periodTab[MIN_PERIOD]))
127 	{
128 		s->finetune = -128;
129 		s->relativeNote = -48;
130 		return;
131 	}
132 
133 	if (midCFreq >= (int32_t)dGetHzFromPeriod(periodTab[MAX_PERIOD]))
134 	{
135 		s->finetune = 127;
136 		s->relativeNote = 71;
137 		return;
138 	}
139 
140 	// check if midCFreq is matching any of the non-finetuned note frequencies (C-0..B-9)
141 
142 	for (int8_t i = 0; i < 10*12; i++)
143 	{
144 		if (midCFreq == (int32_t)dGetHzFromPeriod(periodTab[16 + (i<<4)]))
145 		{
146 			s->finetune = 0;
147 			s->relativeNote = i - NOTE_C4;
148 			return;
149 		}
150 	}
151 
152 	// find closest frequency in period table
153 
154 	int32_t period = MAX_PERIOD;
155 	for (; period >= MIN_PERIOD; period--)
156 	{
157 		const int32_t curr = (int32_t)dGetHzFromPeriod(periodTab[period]);
158 		if (midCFreq == curr)
159 			break;
160 
161 		if (midCFreq > curr)
162 		{
163 			const int32_t next = (int32_t)dGetHzFromPeriod(periodTab[period+1]);
164 			const int32_t errorCurr = ABS(curr-midCFreq);
165 			const int32_t errorNext = ABS(next-midCFreq);
166 
167 			if (errorCurr <= errorNext)
168 				break; // current is the closest
169 
170 			period++;
171 			break; // current+1 is the closest
172 		}
173 	}
174 
175 	s->finetune = ((period & 31) - 16) << 3;
176 	s->relativeNote = (int8_t)(((period & ~31) >> 4) - NOTE_C4);
177 }
178 
setPatternLen(uint16_t pattNum,int16_t numRows)179 void setPatternLen(uint16_t pattNum, int16_t numRows)
180 {
181 	assert(pattNum < MAX_PATTERNS);
182 	if ((numRows < 1 || numRows > MAX_PATT_LEN) || numRows == patternNumRows[pattNum])
183 		return;
184 
185 	const bool audioWasntLocked = !audio.locked;
186 	if (audioWasntLocked)
187 		lockAudio();
188 
189 	patternNumRows[pattNum] = numRows;
190 
191 	if (pattern[pattNum] != NULL)
192 		killPatternIfUnused(pattNum);
193 
194 	// non-FT2 security
195 	song.pattDelTime = 0;
196 	song.pattDelTime2 = 0;
197 	song.pBreakFlag = false;
198 	song.posJumpFlag = false;
199 	song.pBreakPos = 0;
200 
201 	song.currNumRows = numRows;
202 	if (song.row >= song.currNumRows)
203 	{
204 		song.row = song.currNumRows - 1;
205 		editor.row = song.row;
206 	}
207 
208 	checkMarkLimits();
209 
210 	if (audioWasntLocked)
211 		unlockAudio();
212 
213 	ui.updatePatternEditor = true;
214 	ui.updatePosSections = true;
215 }
216 
getUsedSamples(int16_t smpNum)217 int16_t getUsedSamples(int16_t smpNum)
218 {
219 	if (instr[smpNum] == NULL)
220 		return 0;
221 
222 	instr_t *ins = instr[smpNum];
223 
224 	int16_t i = 16 - 1;
225 	while (i >= 0 && ins->smp[i].dataPtr == NULL && ins->smp[i].name[0] == '\0')
226 		i--;
227 
228 	/* Yes, 'i' can be -1 here, and will be set to at least 0
229 	** because of ins->ta values. Possibly an FT2 bug...
230 	*/
231 	for (int16_t j = 0; j < 96; j++)
232 	{
233 		if (ins->note2SampleLUT[j] > i)
234 			i = ins->note2SampleLUT[j];
235 	}
236 
237 	return i+1;
238 }
239 
getRealUsedSamples(int16_t smpNum)240 int16_t getRealUsedSamples(int16_t smpNum)
241 {
242 	if (instr[smpNum] == NULL)
243 		return 0;
244 
245 	int8_t i = 16 - 1;
246 	while (i >= 0 && instr[smpNum]->smp[i].dataPtr == NULL)
247 		i--;
248 
249 	return i+1;
250 }
251 
dLinearPeriod2Hz(int32_t period)252 double dLinearPeriod2Hz(int32_t period)
253 {
254 	period &= 0xFFFF; // just in case (actual period range is 0..65535)
255 
256 	if (period == 0)
257 		return 0.0; // in FT2, a period of 0 results in 0Hz
258 
259 	const uint32_t invPeriod = ((12 * 192 * 4) - period) & 0xFFFF; // mask needed for FT2 period overflow quirk
260 
261 	const uint32_t quotient  = invPeriod / (12 * 16 * 4);
262 	const uint32_t remainder = invPeriod % (12 * 16 * 4);
263 
264 	return dLogTab[remainder] * dExp2MulTab[(14-quotient) & 31]; // x = y >> ((14-quotient) & 31);
265 }
266 
dAmigaPeriod2Hz(int32_t period)267 double dAmigaPeriod2Hz(int32_t period)
268 {
269 	period &= 0xFFFF; // just in case (actual period range is 0..65535)
270 
271 	if (period == 0)
272 		return 0.0; // in FT2, a period of 0 results in 0Hz
273 
274 	return (double)(8363 * 1712) / period;
275 }
276 
dPeriod2Hz(int32_t period)277 double dPeriod2Hz(int32_t period)
278 {
279 	return audio.linearPeriodsFlag ? dLinearPeriod2Hz(period) : dAmigaPeriod2Hz(period);
280 }
281 
282 // returns *exact* FT2 C-4 voice rate (depending on finetune, relativeNote and linear/Amiga period mode)
getSampleC4Rate(sample_t * s)283 double getSampleC4Rate(sample_t *s)
284 {
285 	int32_t note = NOTE_C4 + s->relativeNote;
286 	if (note < 0)
287 		return -1; // shouldn't happen (just in case...)
288 
289 	if (note >= (10*12)-1)
290 		return -1; // B-9 (after relativeTone add) = illegal! (won't play in replayer)
291 
292 	const int32_t C4Period = (note << 4) + (((int8_t)s->finetune >> 3) + 16);
293 
294 	const int32_t period = audio.linearPeriodsFlag ? linearPeriods[C4Period] : amigaPeriods[C4Period];
295 	return dPeriod2Hz(period);
296 }
297 
setFrequencyTable(bool linearPeriodsFlag)298 void setFrequencyTable(bool linearPeriodsFlag)
299 {
300 	pauseAudio();
301 
302 	audio.linearPeriodsFlag = linearPeriodsFlag;
303 
304 	if (audio.linearPeriodsFlag)
305 		note2Period = linearPeriods;
306 	else
307 		note2Period = amigaPeriods;
308 
309 	resumeAudio();
310 
311 	if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_IO_DEVICES)
312 	{
313 		// update "frequency table" radiobutton, if it's shown
314 		setConfigIORadioButtonStates();
315 
316 		// update mid-C freq. in instr. editor (it can slightly differ between Amiga/linear)
317 		if (ui.instEditorShown)
318 			drawC4Rate();
319 	}
320 }
321 
retrigVolume(channel_t * ch)322 static void retrigVolume(channel_t *ch)
323 {
324 	ch->realVol = ch->oldVol;
325 	ch->outVol = ch->oldVol;
326 	ch->outPan = ch->oldPan;
327 	ch->status |= IS_Vol + IS_Pan + IS_QuickVol;
328 }
329 
retrigEnvelopeVibrato(channel_t * ch)330 static void retrigEnvelopeVibrato(channel_t *ch)
331 {
332 	if (!(ch->waveCtrl & 0x04)) ch->vibPos  = 0;
333 	if (!(ch->waveCtrl & 0x40)) ch->tremPos = 0;
334 
335 	ch->retrigCnt = 0;
336 	ch->tremorPos = 0;
337 
338 	ch->envSustainActive = true;
339 
340 	instr_t *ins = ch->instrPtr;
341 	assert(ins != NULL);
342 
343 	if (ins->volEnvFlags & ENV_ENABLED)
344 	{
345 		ch->volEnvTick = 65535;
346 		ch->volEnvPos = 0;
347 	}
348 
349 	if (ins->panEnvFlags & ENV_ENABLED)
350 	{
351 		ch->panEnvTick = 65535;
352 		ch->panEnvPos = 0;
353 	}
354 
355 	ch->fadeoutSpeed = ins->fadeout; // FT2 doesn't check if fadeout is more than 4095!
356 	ch->fadeoutVol = 32768;
357 
358 	if (ins->vibDepth > 0)
359 	{
360 		ch->eVibPos = 0;
361 
362 		if (ins->vibSweep > 0)
363 		{
364 			ch->eVibAmp = 0;
365 			ch->eVibSweep = (ins->vibDepth << 8) / ins->vibSweep;
366 		}
367 		else
368 		{
369 			ch->eVibAmp = ins->vibDepth << 8;
370 			ch->eVibSweep = 0;
371 		}
372 	}
373 }
374 
keyOff(channel_t * ch)375 void keyOff(channel_t *ch)
376 {
377 	ch->envSustainActive = false;
378 
379 	instr_t *ins = ch->instrPtr;
380 	assert(ins != NULL);
381 
382 	if (ins->volEnvFlags & ENV_ENABLED)
383 	{
384 		if (ch->volEnvTick >= (uint16_t)ins->volEnvPoints[ch->volEnvPos][0])
385 			ch->volEnvTick = ins->volEnvPoints[ch->volEnvPos][0] - 1;
386 	}
387 	else
388 	{
389 		ch->realVol = 0;
390 		ch->outVol = 0;
391 		ch->status |= IS_Vol + IS_QuickVol;
392 	}
393 
394 	if (!(ins->panEnvFlags & ENV_ENABLED)) // What..? Probably an FT2 bug.
395 	{
396 		if (ch->panEnvTick >= (uint16_t)ins->panEnvPoints[ch->panEnvPos][0])
397 			ch->panEnvTick = ins->panEnvPoints[ch->panEnvPos][0] - 1;
398 	}
399 }
400 
calcReplayerLogTab(void)401 void calcReplayerLogTab(void) // for linear period -> hz calculation
402 {
403 	for (int32_t i = 0; i < 32; i++)
404 		dExp2MulTab[i] = 1.0 / exp2(i); // 1/(2^i)
405 
406 	for (int32_t i = 0; i < 4*12*16; i++)
407 		dLogTab[i] = 8363.0 * exp2(i / 768.0) * 256.0;
408 }
409 
calcReplayerVars(int32_t audioFreq)410 void calcReplayerVars(int32_t audioFreq)
411 {
412 	assert(audioFreq > 0);
413 	if (audioFreq <= 0)
414 		return;
415 
416 	audio.dHz2MixDeltaMul = (double)MIXER_FRAC_SCALE / audioFreq;
417 	audio.quickVolRampSamples = (int32_t)round(audioFreq / (double)FT2_QUICKRAMP_SAMPLES);
418 	audio.fRampQuickVolMul = (float)(1.0 / audio.quickVolRampSamples);
419 
420 	for (int32_t bpm = MIN_BPM; bpm <= MAX_BPM; bpm++)
421 	{
422 		const int32_t i = bpm - MIN_BPM; // index for tables
423 
424 		const double dBpmHz = bpm / 2.5;
425 		const double dSamplesPerTick = audioFreq / dBpmHz;
426 
427 		// convert to 32.32 fixed-point
428 		audio.samplesPerTick64Tab[i] = (int64_t)((dSamplesPerTick * (UINT32_MAX+1.0)) + 0.5); // rounded
429 
430 		// BPM Hz -> tick length for performance counter (syncing visuals to audio)
431 		double dTimeInt;
432 		double dTimeFrac = modf(editor.dPerfFreq / dBpmHz, &dTimeInt);
433 		const int32_t timeInt = (int32_t)dTimeInt;
434 
435 		dTimeFrac = floor((UINT32_MAX+1.0) * dTimeFrac); // fractional part (scaled to 0..2^32-1)
436 
437 		audio.tickTimeTab[i] = (uint32_t)timeInt;
438 		audio.tickTimeFracTab[i] = (uint32_t)dTimeFrac;
439 
440 		// for calculating volume ramp length for tick-lenghted ramps
441 		const int32_t samplesPerTickRounded = (int32_t)(dSamplesPerTick + 0.5); // must be rounded
442 		audio.fRampTickMulTab[i] = (float)(1.0 / samplesPerTickRounded);
443 	}
444 }
445 
446 // for piano in Instr. Ed. (values outside 0..95 can happen)
getPianoKey(uint16_t period,int8_t finetune,int8_t relativeNote)447 int32_t getPianoKey(uint16_t period, int8_t finetune, int8_t relativeNote)
448 {
449 	assert(note2Period != NULL);
450 	if (period > note2Period[0])
451 		return -1; // outside left piano edge
452 
453 	finetune = ((int8_t)finetune >> 3) + 16; // -128..127 -> 0..31
454 
455 	int32_t hiPeriod = 10*12*16;
456 	int32_t loPeriod = 0;
457 
458 	for (int32_t i = 0; i < 7; i++)
459 	{
460 		const int32_t tmpPeriod = (((loPeriod + hiPeriod) >> 1) & ~15) + finetune;
461 
462 		int32_t lookUp = tmpPeriod - 16;
463 		if (lookUp < 0)
464 			lookUp = 0;
465 
466 		if (period >= note2Period[lookUp])
467 			hiPeriod = (tmpPeriod - finetune) & ~15;
468 		else
469 			loPeriod = (tmpPeriod - finetune) & ~15;
470 	}
471 
472 	return (loPeriod >> 4) - relativeNote;
473 }
474 
startTone(uint8_t note,uint8_t efx,uint8_t efxData,channel_t * ch)475 static void startTone(uint8_t note, uint8_t efx, uint8_t efxData, channel_t *ch)
476 {
477 	if (note == NOTE_OFF)
478 	{
479 		keyOff(ch);
480 		return;
481 	}
482 
483 	// if we came from Rxy (retrig), we didn't check note (Ton) yet
484 	if (note == 0)
485 	{
486 		note = ch->noteNum;
487 		if (note == 0)
488 			return; // if still no note, exit from routine
489 	}
490 
491 	ch->noteNum = note;
492 
493 	assert(ch->instrNum <= 130);
494 	instr_t *ins = instr[ch->instrNum];
495 	if (ins == NULL)
496 		ins = instr[0]; // empty instruments use this placeholder instrument
497 
498 	ch->instrPtr = ins;
499 	ch->mute = ins->mute;
500 
501 	if (note > 96) // non-FT2 security (should never happen because I clamp in the patt. loader now)
502 		note = 96;
503 
504 	ch->smpNum = ins->note2SampleLUT[note-1] & 0xF; // FT2 doesn't AND here, but let's do it for safety
505 	sample_t *s = &ins->smp[ch->smpNum];
506 
507 	ch->smpPtr = s;
508 	ch->relativeNote = s->relativeNote;
509 
510 	note += ch->relativeNote;
511 	if (note >= 10*12) // unsigned check (also handles note < 0)
512 		return;
513 
514 	ch->oldVol = s->volume;
515 	ch->oldPan = s->panning;
516 
517 	if (efx == 0xE && (efxData & 0xF0) == 0x50)
518 		ch->finetune = ((efxData & 0x0F) << 4) - 128;
519 	else
520 		ch->finetune = s->finetune;
521 
522 	if (note != 0)
523 	{
524 		const uint16_t noteIndex = ((note-1) << 4) + (((int8_t)ch->finetune >> 3) + 16); // 0..1920
525 
526 		assert(note2Period != NULL);
527 		ch->outPeriod = ch->realPeriod = note2Period[noteIndex];
528 	}
529 
530 	ch->status |= IS_Period + IS_Vol + IS_Pan + IS_Trigger + IS_QuickVol;
531 
532 	if (efx == 9)
533 	{
534 		if (efxData > 0)
535 			ch->smpOffset = ch->efxData;
536 
537 		ch->smpStartPos = ch->smpOffset << 8;
538 	}
539 	else
540 	{
541 		ch->smpStartPos = 0;
542 	}
543 }
544 
545 static void volume(channel_t *ch, uint8_t param); // volume slide
546 static void vibrato2(channel_t *ch);
547 static void tonePorta(channel_t *ch, uint8_t param);
548 
dummy(channel_t * ch,uint8_t param)549 static void dummy(channel_t *ch, uint8_t param)
550 {
551 	(void)ch;
552 	(void)param;
553 	return;
554 }
555 
finePortaUp(channel_t * ch,uint8_t param)556 static void finePortaUp(channel_t *ch, uint8_t param)
557 {
558 	if (param == 0)
559 		param = ch->fPortaUpSpeed;
560 
561 	ch->fPortaUpSpeed = param;
562 
563 	ch->realPeriod -= param << 2;
564 	if ((int16_t)ch->realPeriod < 1)
565 		ch->realPeriod = 1;
566 
567 	ch->outPeriod = ch->realPeriod;
568 	ch->status |= IS_Period;
569 }
570 
finePortaDown(channel_t * ch,uint8_t param)571 static void finePortaDown(channel_t *ch, uint8_t param)
572 {
573 	if (param == 0)
574 		param = ch->fPortaDownSpeed;
575 
576 	ch->fPortaDownSpeed = param;
577 
578 	ch->realPeriod += param << 2;
579 	if ((int16_t)ch->realPeriod > MAX_FRQ-1) // FT2 bug, should've been unsigned comparison
580 		ch->realPeriod = MAX_FRQ-1;
581 
582 	ch->outPeriod = ch->realPeriod;
583 	ch->status |= IS_Period;
584 }
585 
setGlissCtrl(channel_t * ch,uint8_t param)586 static void setGlissCtrl(channel_t *ch, uint8_t param)
587 {
588 	ch->glissFunk = param;
589 }
590 
setVibratoCtrl(channel_t * ch,uint8_t param)591 static void setVibratoCtrl(channel_t *ch, uint8_t param)
592 {
593 	ch->waveCtrl = (ch->waveCtrl & 0xF0) | param;
594 }
595 
jumpLoop(channel_t * ch,uint8_t param)596 static void jumpLoop(channel_t *ch, uint8_t param)
597 {
598 	if (param == 0)
599 	{
600 		ch->jumpToRow = song.row & 0xFF;
601 	}
602 	else if (ch->patLoopCounter == 0)
603 	{
604 		ch->patLoopCounter = param;
605 
606 		song.pBreakPos = ch->jumpToRow;
607 		song.pBreakFlag = true;
608 	}
609 	else if (--ch->patLoopCounter > 0)
610 	{
611 		song.pBreakPos = ch->jumpToRow;
612 		song.pBreakFlag = true;
613 	}
614 }
615 
setTremoloCtrl(channel_t * ch,uint8_t param)616 static void setTremoloCtrl(channel_t *ch, uint8_t param)
617 {
618 	ch->waveCtrl = (param << 4) | (ch->waveCtrl & 0x0F);
619 }
620 
volFineUp(channel_t * ch,uint8_t param)621 static void volFineUp(channel_t *ch, uint8_t param)
622 {
623 	if (param == 0)
624 		param = ch->fVolSlideUpSpeed;
625 
626 	ch->fVolSlideUpSpeed = param;
627 
628 	ch->realVol += param;
629 	if (ch->realVol > 64)
630 		ch->realVol = 64;
631 
632 	ch->outVol = ch->realVol;
633 	ch->status |= IS_Vol;
634 }
635 
volFineDown(channel_t * ch,uint8_t param)636 static void volFineDown(channel_t *ch, uint8_t param)
637 {
638 	if (param == 0)
639 		param = ch->fVolSlideDownSpeed;
640 
641 	ch->fVolSlideDownSpeed = param;
642 
643 	ch->realVol -= param;
644 	if ((int8_t)ch->realVol < 0)
645 		ch->realVol = 0;
646 
647 	ch->outVol = ch->realVol;
648 	ch->status |= IS_Vol;
649 }
650 
noteCut0(channel_t * ch,uint8_t param)651 static void noteCut0(channel_t *ch, uint8_t param)
652 {
653 	if (param == 0) // only a parameter of zero is handled here
654 	{
655 		ch->realVol = 0;
656 		ch->outVol = 0;
657 		ch->status |= IS_Vol + IS_QuickVol;
658 	}
659 }
660 
pattDelay(channel_t * ch,uint8_t param)661 static void pattDelay(channel_t *ch, uint8_t param)
662 {
663 	if (song.pattDelTime2 == 0)
664 		song.pattDelTime = param + 1;
665 
666 	(void)ch;
667 }
668 
669 static const efxRoutine EJumpTab_TickZero[16] =
670 {
671 	dummy, // 0
672 	finePortaUp, // 1
673 	finePortaDown, // 2
674 	setGlissCtrl, // 3
675 	setVibratoCtrl, // 4
676 	dummy, // 5
677 	jumpLoop, // 6
678 	setTremoloCtrl, // 7
679 	dummy, // 8
680 	dummy, // 9
681 	volFineUp, // A
682 	volFineDown, // B
683 	noteCut0, // C
684 	dummy, // D
685 	pattDelay, // E
686 	dummy // F
687 };
688 
E_Effects_TickZero(channel_t * ch,uint8_t param)689 static void E_Effects_TickZero(channel_t *ch, uint8_t param)
690 {
691 	const uint8_t efx = param >> 4;
692 	param &= 0x0F;
693 
694 	if (ch->channelOff) // channel is muted, only handle some E effects
695 	{
696 		     if (efx == 0x6) jumpLoop(ch, param);
697 		else if (efx == 0xE) pattDelay(ch, param);
698 
699 		return;
700 	}
701 
702 	EJumpTab_TickZero[efx](ch, param);
703 }
704 
posJump(channel_t * ch,uint8_t param)705 static void posJump(channel_t *ch, uint8_t param)
706 {
707 	if (playMode != PLAYMODE_PATT && playMode != PLAYMODE_RECPATT)
708 	{
709 		const int16_t pos = (int16_t)param - 1;
710 		if (pos < 0 || pos >= song.songLength)
711 			bxxOverflow = true; // non-FT2 security fix...
712 		else
713 			song.songPos = pos;
714 	}
715 
716 	song.pBreakPos = 0;
717 	song.posJumpFlag = true;
718 
719 	(void)ch;
720 }
721 
pattBreak(channel_t * ch,uint8_t param)722 static void pattBreak(channel_t *ch, uint8_t param)
723 {
724 	param = ((param >> 4) * 10) + (param & 0x0F);
725 	if (param <= 63)
726 		song.pBreakPos = param;
727 	else
728 		song.pBreakPos = 0;
729 
730 	song.posJumpFlag = true;
731 
732 	(void)ch;
733 }
734 
setSpeed(channel_t * ch,uint8_t param)735 static void setSpeed(channel_t *ch, uint8_t param)
736 {
737 	if (param >= 32)
738 	{
739 		song.BPM = param;
740 		setMixerBPM(song.BPM);
741 	}
742 	else
743 	{
744 		song.tick = song.speed = param;
745 	}
746 
747 	(void)ch;
748 }
749 
setGlobalVolume(channel_t * ch,uint8_t param)750 static void setGlobalVolume(channel_t *ch, uint8_t param)
751 {
752 	if (param > 64)
753 		param = 64;
754 
755 	song.globalVolume = param;
756 
757 	channel_t *c = channel;
758 	for (int32_t i = 0; i < song.numChannels; i++, c++) // update all voice volumes
759 		c->status |= IS_Vol;
760 
761 	(void)ch;
762 }
763 
setEnvelopePos(channel_t * ch,uint8_t param)764 static void setEnvelopePos(channel_t *ch, uint8_t param)
765 {
766 	bool envUpdate;
767 	int8_t point;
768 	int16_t tick;
769 
770 	instr_t *ins = ch->instrPtr;
771 	assert(ins != NULL);
772 
773 	// (envelope precision has been updated from x.8fp to x.16fp)
774 
775 	// *** VOLUME ENVELOPE ***
776 	if (ins->volEnvFlags & ENV_ENABLED)
777 	{
778 		ch->volEnvTick = param-1;
779 
780 		point = 0;
781 		envUpdate = true;
782 		tick = param;
783 
784 		if (ins->volEnvLength > 1)
785 		{
786 			point++;
787 			for (int32_t i = 0; i < ins->volEnvLength-1; i++)
788 			{
789 				if (tick < ins->volEnvPoints[point][0])
790 				{
791 					point--;
792 
793 					tick -= ins->volEnvPoints[point][0];
794 					if (tick == 0)
795 					{
796 						envUpdate = false;
797 						break;
798 					}
799 
800 					if (ins->volEnvPoints[point+1][0] <= ins->volEnvPoints[point][0])
801 					{
802 						envUpdate = true;
803 						break;
804 					}
805 
806 					int32_t delta = (int8_t)((ins->volEnvPoints[point+1][1] - ins->volEnvPoints[point][1]) & 0xFF) << 16;
807 					delta /= (ins->volEnvPoints[point+1][0]-ins->volEnvPoints[point][0]);
808 
809 					ch->volEnvDelta = delta;
810 					ch->volEnvValue = (ch->volEnvDelta * (tick-1)) + ((int8_t)(ins->volEnvPoints[point][1] & 0xFF) << 16);
811 
812 					point++;
813 
814 					envUpdate = false;
815 					break;
816 				}
817 
818 				point++;
819 			}
820 
821 			if (envUpdate)
822 				point--;
823 		}
824 
825 		if (envUpdate)
826 		{
827 			ch->volEnvDelta = 0;
828 			ch->volEnvValue = (int8_t)(ins->volEnvPoints[point][1] & 0xFF) << 16;
829 		}
830 
831 		if (point >= ins->volEnvLength)
832 		{
833 			point = ins->volEnvLength-1;
834 			if (point < 0)
835 				point = 0;
836 		}
837 
838 		ch->volEnvPos = point;
839 	}
840 
841 	// *** PANNING ENVELOPE ***
842 	if (ins->volEnvFlags & ENV_SUSTAIN) // What..? An FT2 bug!?
843 	{
844 		ch->panEnvTick = param-1;
845 
846 		point = 0;
847 		envUpdate = true;
848 		tick = param;
849 
850 		if (ins->panEnvLength > 1)
851 		{
852 			point++;
853 			for (int32_t i = 0; i < ins->panEnvLength-1; i++)
854 			{
855 				if (tick < ins->panEnvPoints[point][0])
856 				{
857 					point--;
858 
859 					tick -= ins->panEnvPoints[point][0];
860 					if (tick == 0)
861 					{
862 						envUpdate = false;
863 						break;
864 					}
865 
866 					if (ins->panEnvPoints[point+1][0] <= ins->panEnvPoints[point][0])
867 					{
868 						envUpdate = true;
869 						break;
870 					}
871 
872 					int32_t delta = (int8_t)((ins->panEnvPoints[point+1][1] - ins->panEnvPoints[point][1]) & 0xFF) << 16;
873 					delta /= (ins->panEnvPoints[point+1][0]-ins->panEnvPoints[point][0]);
874 
875 					ch->panEnvDelta = delta;
876 					ch->panEnvValue = (ch->panEnvDelta * (tick-1)) + ((int8_t)(ins->panEnvPoints[point][1] & 0xFF) << 16);
877 
878 					point++;
879 
880 					envUpdate = false;
881 					break;
882 				}
883 
884 				point++;
885 			}
886 
887 			if (envUpdate)
888 				point--;
889 		}
890 
891 		if (envUpdate)
892 		{
893 			ch->panEnvDelta = 0;
894 			ch->panEnvValue = (int8_t)(ins->panEnvPoints[point][1] & 0xFF) << 16;
895 		}
896 
897 		if (point >= ins->panEnvLength)
898 		{
899 			point = ins->panEnvLength-1;
900 			if (point < 0)
901 				point = 0;
902 		}
903 
904 		ch->panEnvPos = point;
905 	}
906 }
907 
908 static const efxRoutine JumpTab_TickZero[36] =
909 {
910 	dummy, // 0
911 	dummy, // 1
912 	dummy, // 2
913 	dummy, // 3
914 	dummy, // 4
915 	dummy, // 5
916 	dummy, // 6
917 	dummy, // 7
918 	dummy, // 8
919 	dummy, // 9
920 	dummy, // A
921 	posJump, // B
922 	dummy, // C
923 	pattBreak, // D
924 	E_Effects_TickZero, // E
925 	setSpeed, // F
926 	setGlobalVolume, // G
927 	dummy, // H
928 	dummy, // I
929 	dummy, // J
930 	dummy, // K
931 	setEnvelopePos, // L
932 	dummy, // M
933 	dummy, // N
934 	dummy, // O
935 	dummy, // P
936 	dummy, // Q
937 	dummy, // R
938 	dummy, // S
939 	dummy, // T
940 	dummy, // U
941 	dummy, // V
942 	dummy, // W
943 	dummy, // X
944 	dummy, // Y
945 	dummy  // Z
946 };
947 
handleMoreEffects_TickZero(channel_t * ch)948 static void handleMoreEffects_TickZero(channel_t *ch) // called even if channel is muted
949 {
950 	if (ch->efx > 35)
951 		return;
952 
953 	JumpTab_TickZero[ch->efx](ch, ch->efxData);
954 }
955 
956 /* -- tick-zero volume column effects --
957 ** 2nd parameter is used for a volume column quirk with the Rxy command (multiretrig)
958 */
959 
v_SetVibSpeed(channel_t * ch,uint8_t * volColumnData)960 static void v_SetVibSpeed(channel_t *ch, uint8_t *volColumnData)
961 {
962 	*volColumnData = (ch->volColumnVol & 0x0F) << 2;
963 	if (*volColumnData != 0)
964 		ch->vibSpeed = *volColumnData;
965 }
966 
v_Volume(channel_t * ch,uint8_t * volColumnData)967 static void v_Volume(channel_t *ch, uint8_t *volColumnData)
968 {
969 	*volColumnData -= 16;
970 	if (*volColumnData > 64) // no idea why FT2 has this check...
971 		*volColumnData = 64;
972 
973 	ch->outVol = ch->realVol = *volColumnData;
974 	ch->status |= IS_Vol + IS_QuickVol;
975 }
976 
v_FineSlideDown(channel_t * ch,uint8_t * volColumnData)977 static void v_FineSlideDown(channel_t *ch, uint8_t *volColumnData)
978 {
979 	*volColumnData = (uint8_t)(0 - (ch->volColumnVol & 0x0F)) + ch->realVol;
980 	if ((int8_t)*volColumnData < 0)
981 		*volColumnData = 0;
982 
983 	ch->outVol = ch->realVol = *volColumnData;
984 	ch->status |= IS_Vol;
985 }
986 
v_FineSlideUp(channel_t * ch,uint8_t * volColumnData)987 static void v_FineSlideUp(channel_t *ch, uint8_t *volColumnData)
988 {
989 	*volColumnData = (ch->volColumnVol & 0x0F) + ch->realVol;
990 	if (*volColumnData > 64)
991 		*volColumnData = 64;
992 
993 	ch->outVol = ch->realVol = *volColumnData;
994 	ch->status |= IS_Vol;
995 }
996 
v_SetPan(channel_t * ch,uint8_t * volColumnData)997 static void v_SetPan(channel_t *ch, uint8_t *volColumnData)
998 {
999 	*volColumnData <<= 4;
1000 
1001 	ch->outPan = *volColumnData;
1002 	ch->status |= IS_Pan;
1003 }
1004 
1005 // -- non-tick-zero volume column effects --
1006 
v_SlideDown(channel_t * ch)1007 static void v_SlideDown(channel_t *ch)
1008 {
1009 	uint8_t newVol = (uint8_t)(0 - (ch->volColumnVol & 0x0F)) + ch->realVol;
1010 	if ((int8_t)newVol < 0)
1011 		newVol = 0;
1012 
1013 	ch->outVol = ch->realVol = newVol;
1014 	ch->status |= IS_Vol;
1015 }
1016 
v_SlideUp(channel_t * ch)1017 static void v_SlideUp(channel_t *ch)
1018 {
1019 	uint8_t newVol = (ch->volColumnVol & 0x0F) + ch->realVol;
1020 	if (newVol > 64)
1021 		newVol = 64;
1022 
1023 	ch->outVol = ch->realVol = newVol;
1024 	ch->status |= IS_Vol;
1025 }
1026 
v_Vibrato(channel_t * ch)1027 static void v_Vibrato(channel_t *ch)
1028 {
1029 	const uint8_t param = ch->volColumnVol & 0xF;
1030 	if (param > 0)
1031 		ch->vibDepth = param;
1032 
1033 	vibrato2(ch);
1034 }
1035 
v_PanSlideLeft(channel_t * ch)1036 static void v_PanSlideLeft(channel_t *ch)
1037 {
1038 	uint16_t tmp16 = (uint8_t)(0 - (ch->volColumnVol & 0x0F)) + ch->outPan;
1039 	if (tmp16 < 256) // includes an FT2 bug: pan-slide-left of 0 = set pan to 0
1040 		tmp16 = 0;
1041 
1042 	ch->outPan = (uint8_t)tmp16;
1043 	ch->status |= IS_Pan;
1044 }
1045 
v_PanSlideRight(channel_t * ch)1046 static void v_PanSlideRight(channel_t *ch)
1047 {
1048 	uint16_t tmp16 = (ch->volColumnVol & 0x0F) + ch->outPan;
1049 	if (tmp16 > 255)
1050 		tmp16 = 255;
1051 
1052 	ch->outPan = (uint8_t)tmp16;
1053 	ch->status |= IS_Pan;
1054 }
1055 
v_TonePorta(channel_t * ch)1056 static void v_TonePorta(channel_t *ch)
1057 {
1058 	tonePorta(ch, 0); // the last parameter is actually not used in tonePorta()
1059 }
1060 
v_dummy(channel_t * ch)1061 static void v_dummy(channel_t *ch)
1062 {
1063 	(void)ch;
1064 	return;
1065 }
1066 
v_dummy2(channel_t * ch,uint8_t * volColumnData)1067 static void v_dummy2(channel_t *ch, uint8_t *volColumnData)
1068 {
1069 	(void)ch;
1070 	(void)volColumnData;
1071 	return;
1072 }
1073 
1074 static const volColumnEfxRoutine VJumpTab_TickNonZero[16] =
1075 {
1076 	v_dummy,        v_dummy,         v_dummy,  v_dummy,
1077 	v_dummy,        v_dummy,     v_SlideDown, v_SlideUp,
1078 	v_dummy,        v_dummy,         v_dummy, v_Vibrato,
1079 	v_dummy, v_PanSlideLeft, v_PanSlideRight, v_TonePorta
1080 };
1081 
1082 static const volColumnEfxRoutine2 VJumpTab_TickZero[16] =
1083 {
1084 	       v_dummy2,      v_Volume,      v_Volume, v_Volume,
1085 	       v_Volume,      v_Volume,      v_dummy2, v_dummy2,
1086 	v_FineSlideDown, v_FineSlideUp, v_SetVibSpeed, v_dummy2,
1087 	       v_SetPan,      v_dummy2,      v_dummy2, v_dummy2
1088 };
1089 
setPan(channel_t * ch,uint8_t param)1090 static void setPan(channel_t *ch, uint8_t param)
1091 {
1092 	ch->outPan = param;
1093 	ch->status |= IS_Pan;
1094 }
1095 
setVol(channel_t * ch,uint8_t param)1096 static void setVol(channel_t *ch, uint8_t param)
1097 {
1098 	if (param > 64)
1099 		param = 64;
1100 
1101 	ch->outVol = ch->realVol = param;
1102 	ch->status |= IS_Vol + IS_QuickVol;
1103 }
1104 
xFinePorta(channel_t * ch,uint8_t param)1105 static void xFinePorta(channel_t *ch, uint8_t param)
1106 {
1107 	const uint8_t type = param >> 4;
1108 	param &= 0x0F;
1109 
1110 	if (type == 0x1) // extra fine porta up
1111 	{
1112 		if (param == 0)
1113 			param = ch->ePortaUpSpeed;
1114 
1115 		ch->ePortaUpSpeed = param;
1116 
1117 		uint16_t newPeriod = ch->realPeriod;
1118 
1119 		newPeriod -= param;
1120 		if ((int16_t)newPeriod < 1)
1121 			newPeriod = 1;
1122 
1123 		ch->outPeriod = ch->realPeriod = newPeriod;
1124 		ch->status |= IS_Period;
1125 	}
1126 	else if (type == 0x2) // extra fine porta down
1127 	{
1128 		if (param == 0)
1129 			param = ch->ePortaDownSpeed;
1130 
1131 		ch->ePortaDownSpeed = param;
1132 
1133 		uint16_t newPeriod = ch->realPeriod;
1134 
1135 		newPeriod += param;
1136 		if ((int16_t)newPeriod > MAX_FRQ-1) // FT2 bug, should've been unsigned comparison
1137 			newPeriod = MAX_FRQ-1;
1138 
1139 		ch->outPeriod = ch->realPeriod = newPeriod;
1140 		ch->status |= IS_Period;
1141 	}
1142 }
1143 
doMultiRetrig(channel_t * ch,uint8_t param)1144 static void doMultiRetrig(channel_t *ch, uint8_t param) // "param" is never used (needed for efx jumptable structure)
1145 {
1146 	uint8_t cnt = ch->retrigCnt + 1;
1147 	if (cnt < ch->retrigSpeed)
1148 	{
1149 		ch->retrigCnt = cnt;
1150 		return;
1151 	}
1152 
1153 	ch->retrigCnt = 0;
1154 
1155 	int16_t vol = ch->realVol;
1156 	switch (ch->retrigVol)
1157 	{
1158 		case 0x1: vol -= 1; break;
1159 		case 0x2: vol -= 2; break;
1160 		case 0x3: vol -= 4; break;
1161 		case 0x4: vol -= 8; break;
1162 		case 0x5: vol -= 16; break;
1163 		case 0x6: vol = (vol >> 1) + (vol >> 3) + (vol >> 4); break;
1164 		case 0x7: vol >>= 1; break;
1165 		case 0x8: break; // does not change the volume
1166 		case 0x9: vol += 1; break;
1167 		case 0xA: vol += 2; break;
1168 		case 0xB: vol += 4; break;
1169 		case 0xC: vol += 8; break;
1170 		case 0xD: vol += 16; break;
1171 		case 0xE: vol = (vol >> 1) + vol; break;
1172 		case 0xF: vol += vol; break;
1173 		default: break;
1174 	}
1175 	vol = CLAMP(vol, 0, 64);
1176 
1177 	ch->realVol = (uint8_t)vol;
1178 	ch->outVol = ch->realVol;
1179 
1180 	if (ch->volColumnVol >= 0x10 && ch->volColumnVol <= 0x50)
1181 	{
1182 		ch->outVol = ch->volColumnVol - 0x10;
1183 		ch->realVol = ch->outVol;
1184 	}
1185 	else if (ch->volColumnVol >= 0xC0 && ch->volColumnVol <= 0xCF)
1186 	{
1187 		ch->outPan = (ch->volColumnVol & 0x0F) << 4;
1188 	}
1189 
1190 	startTone(0, 0, 0, ch);
1191 
1192 	(void)param;
1193 }
1194 
multiRetrig(channel_t * ch,uint8_t param,uint8_t volumeColumnData)1195 static void multiRetrig(channel_t *ch, uint8_t param, uint8_t volumeColumnData)
1196 {
1197 	uint8_t tmpParam;
1198 
1199 	tmpParam = param & 0x0F;
1200 	if (tmpParam == 0)
1201 		tmpParam = ch->retrigSpeed;
1202 
1203 	ch->retrigSpeed = tmpParam;
1204 
1205 	tmpParam = param >> 4;
1206 	if (tmpParam == 0)
1207 		tmpParam = ch->retrigVol;
1208 
1209 	ch->retrigVol = tmpParam;
1210 
1211 	if (volumeColumnData == 0)
1212 		doMultiRetrig(ch, 0); // the second parameter is never used (needed for efx jumptable structure)
1213 }
1214 
handleEffects_TickZero(channel_t * ch)1215 static void handleEffects_TickZero(channel_t *ch)
1216 {
1217 	// volume column effects
1218 	uint8_t newVolCol = ch->volColumnVol; // manipulated by vol. column effects, then used for multiretrig check (FT2 quirk)
1219 	VJumpTab_TickZero[ch->volColumnVol >> 4](ch, &newVolCol);
1220 
1221 	// normal effects
1222 	const uint8_t param = ch->efxData;
1223 	if (ch->efx == 0 && param == 0)
1224 		return; // no effect
1225 
1226 	     if (ch->efx ==  8) setPan(ch, param);
1227 	else if (ch->efx == 12) setVol(ch, param);
1228 	else if (ch->efx == 27) multiRetrig(ch, param, newVolCol);
1229 	else if (ch->efx == 33) xFinePorta(ch, param);
1230 
1231 	handleMoreEffects_TickZero(ch);
1232 }
1233 
fixTonePorta(channel_t * ch,const note_t * p,uint8_t inst)1234 static void fixTonePorta(channel_t *ch, const note_t *p, uint8_t inst)
1235 {
1236 	if (p->note > 0)
1237 	{
1238 		if (p->note == NOTE_OFF)
1239 		{
1240 			keyOff(ch);
1241 		}
1242 		else
1243 		{
1244 			const uint16_t note = (((p->note-1) + ch->relativeNote) << 4) + (((int8_t)ch->finetune >> 3) + 16);
1245 			if (note < MAX_NOTES)
1246 			{
1247 				assert(note2Period != NULL);
1248 				ch->wantPeriod = note2Period[note];
1249 
1250 				if (ch->wantPeriod == ch->realPeriod)
1251 					ch->portaDirection = 0;
1252 				else if (ch->wantPeriod > ch->realPeriod)
1253 					ch->portaDirection = 1;
1254 				else
1255 					ch->portaDirection = 2;
1256 			}
1257 		}
1258 	}
1259 
1260 	if (inst > 0)
1261 	{
1262 		retrigVolume(ch);
1263 		if (p->note != NOTE_OFF)
1264 			retrigEnvelopeVibrato(ch);
1265 	}
1266 }
1267 
getNewNote(channel_t * ch,const note_t * p)1268 static void getNewNote(channel_t *ch, const note_t *p)
1269 {
1270 	ch->volColumnVol = p->vol;
1271 
1272 	if (ch->efx == 0)
1273 	{
1274 		if (ch->efxData > 0) // we have an arpeggio running, set period back
1275 		{
1276 			ch->outPeriod = ch->realPeriod;
1277 			ch->status |= IS_Period;
1278 		}
1279 	}
1280 	else
1281 	{
1282 		// if we have a vibrato on previous row (ch) that ends at current row (p), set period back
1283 		if ((ch->efx == 4 || ch->efx == 6) && (p->efx != 4 && p->efx != 6))
1284 		{
1285 			ch->outPeriod = ch->realPeriod;
1286 			ch->status |= IS_Period;
1287 		}
1288 	}
1289 
1290 	ch->efx = p->efx;
1291 	ch->efxData = p->efxData;
1292 	ch->noteData = (p->instr << 8) | p->note;
1293 
1294 	if (ch->channelOff) // channel is muted, only handle some effects
1295 	{
1296 		handleMoreEffects_TickZero(ch);
1297 		return;
1298 	}
1299 
1300 	// 'inst' var is used for later if checks...
1301 	uint8_t inst = p->instr;
1302 	if (inst > 0)
1303 	{
1304 		if (inst <= MAX_INST)
1305 			ch->instrNum = inst;
1306 		else
1307 			inst = 0;
1308 	}
1309 
1310 	bool checkEfx = true;
1311 	if (p->efx == 0x0E)
1312 	{
1313 		if (p->efxData >= 0xD1 && p->efxData <= 0xDF)
1314 			return; // we have a note delay (ED1..EDF)
1315 		else if (p->efxData == 0x90)
1316 			checkEfx = false;
1317 	}
1318 
1319 	if (checkEfx)
1320 	{
1321 		if ((ch->volColumnVol & 0xF0) == 0xF0) // gxx
1322 		{
1323 			const uint8_t volColumnData = ch->volColumnVol & 0x0F;
1324 			if (volColumnData > 0)
1325 				ch->portaSpeed = volColumnData << 6;
1326 
1327 			fixTonePorta(ch, p, inst);
1328 			handleEffects_TickZero(ch);
1329 			return;
1330 		}
1331 
1332 		if (p->efx == 3 || p->efx == 5) // 3xx or 5xx
1333 		{
1334 			if (p->efx != 5 && p->efxData != 0)
1335 				ch->portaSpeed = p->efxData << 2;
1336 
1337 			fixTonePorta(ch, p, inst);
1338 			handleEffects_TickZero(ch);
1339 			return;
1340 		}
1341 
1342 		if (p->efx == 0x14 && p->efxData == 0) // K00 (KeyOff - only handle tick 0 here)
1343 		{
1344 			keyOff(ch);
1345 
1346 			if (inst)
1347 				retrigVolume(ch);
1348 
1349 			handleEffects_TickZero(ch);
1350 			return;
1351 		}
1352 
1353 		if (p->note == 0)
1354 		{
1355 			if (inst > 0)
1356 			{
1357 				retrigVolume(ch);
1358 				retrigEnvelopeVibrato(ch);
1359 			}
1360 
1361 			handleEffects_TickZero(ch);
1362 			return;
1363 		}
1364 	}
1365 
1366 	if (p->note == NOTE_OFF)
1367 		keyOff(ch);
1368 	else
1369 		startTone(p->note, p->efx, p->efxData, ch);
1370 
1371 	if (inst > 0)
1372 	{
1373 		retrigVolume(ch);
1374 		if (p->note != NOTE_OFF)
1375 			retrigEnvelopeVibrato(ch);
1376 	}
1377 
1378 	handleEffects_TickZero(ch);
1379 }
1380 
updateChannel(channel_t * ch)1381 static void updateChannel(channel_t *ch)
1382 {
1383 	bool envInterpolateFlag, envDidInterpolate;
1384 	uint8_t envPos;
1385 	int16_t autoVibVal;
1386 	uint16_t autoVibAmp;
1387 	int32_t envVal;
1388 	float fVol;
1389 
1390 	instr_t *ins = ch->instrPtr;
1391 	assert(ins != NULL);
1392 
1393 	// *** FADEOUT ***
1394 	if (!ch->envSustainActive)
1395 	{
1396 		ch->status |= IS_Vol;
1397 
1398 		// unsigned clamp + reset
1399 		if (ch->fadeoutVol >= ch->fadeoutSpeed)
1400 		{
1401 			ch->fadeoutVol -= ch->fadeoutSpeed;
1402 		}
1403 		else
1404 		{
1405 			ch->fadeoutVol = 0;
1406 			ch->fadeoutSpeed = 0;
1407 		}
1408 	}
1409 
1410 	if (!ch->mute)
1411 	{
1412 		// (envelope precision has been updated from x.8fp to x.16fp)
1413 
1414 		// *** VOLUME ENVELOPE ***
1415 		envVal = 0;
1416 		if (ins->volEnvFlags & ENV_ENABLED)
1417 		{
1418 			envDidInterpolate = false;
1419 			envPos = ch->volEnvPos;
1420 
1421 			if (++ch->volEnvTick == ins->volEnvPoints[envPos][0])
1422 			{
1423 				ch->volEnvValue = (int8_t)(ins->volEnvPoints[envPos][1] & 0xFF) << 16;
1424 
1425 				envPos++;
1426 				if (ins->volEnvFlags & ENV_LOOP)
1427 				{
1428 					envPos--;
1429 
1430 					if (envPos == ins->volEnvLoopEnd)
1431 					{
1432 						if (!(ins->volEnvFlags & ENV_SUSTAIN) || envPos != ins->volEnvSustain || ch->envSustainActive)
1433 						{
1434 							envPos = ins->volEnvLoopStart;
1435 							ch->volEnvTick = ins->volEnvPoints[envPos][0];
1436 							ch->volEnvValue = (int8_t)(ins->volEnvPoints[envPos][1] & 0xFF) << 16;
1437 						}
1438 					}
1439 
1440 					envPos++;
1441 				}
1442 
1443 				if (envPos < ins->volEnvLength)
1444 				{
1445 					envInterpolateFlag = true;
1446 					if ((ins->volEnvFlags & ENV_SUSTAIN) && ch->envSustainActive)
1447 					{
1448 						if (envPos-1 == ins->volEnvSustain)
1449 						{
1450 							envPos--;
1451 							ch->volEnvDelta = 0;
1452 							envInterpolateFlag = false;
1453 						}
1454 					}
1455 
1456 					if (envInterpolateFlag)
1457 					{
1458 						ch->volEnvPos = envPos;
1459 
1460 						ch->volEnvDelta = 0;
1461 						if (ins->volEnvPoints[envPos][0] > ins->volEnvPoints[envPos-1][0])
1462 						{
1463 							int32_t delta = (int8_t)((ins->volEnvPoints[envPos][1] - ins->volEnvPoints[envPos-1][1]) & 0xFF) << 16;
1464 							delta /= (ins->volEnvPoints[envPos][0]-ins->volEnvPoints[envPos-1][0]);
1465 							ch->volEnvDelta = delta;
1466 
1467 							envVal = ch->volEnvValue;
1468 							envDidInterpolate = true;
1469 						}
1470 					}
1471 				}
1472 				else
1473 				{
1474 					ch->volEnvDelta = 0;
1475 				}
1476 			}
1477 
1478 			if (!envDidInterpolate)
1479 			{
1480 				ch->volEnvValue += ch->volEnvDelta;
1481 
1482 				envVal = ch->volEnvValue;
1483 				if (envVal > 64<<16)
1484 				{
1485 					if (envVal > 128<<16)
1486 						envVal = 64<<16;
1487 					else
1488 						envVal = 0;
1489 
1490 					ch->volEnvDelta = 0;
1491 				}
1492 			}
1493 
1494 			const int32_t vol = song.globalVolume * ch->outVol * ch->fadeoutVol;
1495 
1496 			fVol = vol * (1.0f / (64.0f * 64.0f * 32768.0f));
1497 			fVol *= (int32_t)envVal * (1.0f / (64.0f * (1 << 16))); // volume envelope value
1498 
1499 			ch->status |= IS_Vol; // update mixer vol every tick when vol envelope is enabled
1500 		}
1501 		else
1502 		{
1503 			const int32_t vol = song.globalVolume * ch->outVol * ch->fadeoutVol;
1504 			fVol = vol * (1.0f / (64.0f * 64.0f * 32768.0f));
1505 		}
1506 
1507 		/* FT2 doesn't clamp here, but it's actually important if you
1508 		** move envelope points with the mouse while playing the instrument.
1509 		*/
1510 		ch->fFinalVol = CLAMP(fVol, 0.0f, 1.0f);
1511 	}
1512 	else
1513 	{
1514 		ch->fFinalVol = 0.0f;
1515 	}
1516 
1517 	// *** PANNING ENVELOPE ***
1518 
1519 	envVal = 0;
1520 	if (ins->panEnvFlags & ENV_ENABLED)
1521 	{
1522 		envDidInterpolate = false;
1523 		envPos = ch->panEnvPos;
1524 
1525 		if (++ch->panEnvTick == ins->panEnvPoints[envPos][0])
1526 		{
1527 			ch->panEnvValue = (int8_t)(ins->panEnvPoints[envPos][1] & 0xFF) << 16;
1528 
1529 			envPos++;
1530 			if (ins->panEnvFlags & ENV_LOOP)
1531 			{
1532 				envPos--;
1533 
1534 				if (envPos == ins->panEnvLoopEnd)
1535 				{
1536 					if (!(ins->panEnvFlags & ENV_SUSTAIN) || envPos != ins->panEnvSustain || ch->envSustainActive)
1537 					{
1538 						envPos = ins->panEnvLoopStart;
1539 
1540 						ch->panEnvTick = ins->panEnvPoints[envPos][0];
1541 						ch->panEnvValue = (int8_t)(ins->panEnvPoints[envPos][1] & 0xFF) << 16;
1542 					}
1543 				}
1544 
1545 				envPos++;
1546 			}
1547 
1548 			if (envPos < ins->panEnvLength)
1549 			{
1550 				envInterpolateFlag = true;
1551 				if ((ins->panEnvFlags & ENV_SUSTAIN) && ch->envSustainActive)
1552 				{
1553 					if (envPos-1 == ins->panEnvSustain)
1554 					{
1555 						envPos--;
1556 						ch->panEnvDelta = 0;
1557 						envInterpolateFlag = false;
1558 					}
1559 				}
1560 
1561 				if (envInterpolateFlag)
1562 				{
1563 					ch->panEnvPos = envPos;
1564 
1565 					ch->panEnvDelta = 0;
1566 					if (ins->panEnvPoints[envPos][0] > ins->panEnvPoints[envPos-1][0])
1567 					{
1568 						int32_t delta = (int8_t)((ins->panEnvPoints[envPos][1] - ins->panEnvPoints[envPos-1][1]) & 0xFF) << 16;
1569 						delta /= (ins->panEnvPoints[envPos][0]-ins->panEnvPoints[envPos-1][0]);
1570 						ch->panEnvDelta = delta;
1571 
1572 						envVal = ch->panEnvValue;
1573 						envDidInterpolate = true;
1574 					}
1575 				}
1576 			}
1577 			else
1578 			{
1579 				ch->panEnvDelta = 0;
1580 			}
1581 		}
1582 
1583 		if (!envDidInterpolate)
1584 		{
1585 			ch->panEnvValue += ch->panEnvDelta;
1586 
1587 			envVal = ch->panEnvValue;
1588 			if (envVal > 64<<16)
1589 			{
1590 				if (envVal > 128<<16)
1591 					envVal = 64<<16;
1592 				else
1593 					envVal = 0;
1594 
1595 				ch->panEnvDelta = 0;
1596 			}
1597 		}
1598 
1599 		envVal -= 32<<16; // center panning envelope value
1600 
1601 		const int32_t pan = 128 - ABS(ch->outPan-128);
1602 		const int32_t panAdd = (pan * envVal) >> (16+5);
1603 		ch->finalPan = (uint8_t)(ch->outPan + panAdd);
1604 
1605 		ch->status |= IS_Pan; // update pan every tick because pan envelope is enabled
1606 	}
1607 	else
1608 	{
1609 		ch->finalPan = ch->outPan;
1610 	}
1611 
1612 	// *** AUTO VIBRATO ***
1613 #ifdef HAS_MIDI
1614 	if (ch->midiVibDepth > 0 || ins->vibDepth > 0)
1615 #else
1616 	if (ins->vibDepth > 0)
1617 #endif
1618 	{
1619 		if (ch->eVibSweep > 0)
1620 		{
1621 			autoVibAmp = ch->eVibSweep;
1622 			if (ch->envSustainActive)
1623 			{
1624 				autoVibAmp += ch->eVibAmp;
1625 				if ((autoVibAmp >> 8) > ins->vibDepth)
1626 				{
1627 					autoVibAmp = ins->vibDepth << 8;
1628 					ch->eVibSweep = 0;
1629 				}
1630 
1631 				ch->eVibAmp = autoVibAmp;
1632 			}
1633 		}
1634 		else
1635 		{
1636 			autoVibAmp = ch->eVibAmp;
1637 		}
1638 
1639 #ifdef HAS_MIDI
1640 		// non-FT2 hack to make modulation wheel work when auto vibrato rate is zero
1641 		if (ch->midiVibDepth > 0 && ins->vibRate == 0)
1642 			ins->vibRate = 0x20;
1643 
1644 		autoVibAmp += ch->midiVibDepth;
1645 #endif
1646 		ch->eVibPos += ins->vibRate;
1647 
1648 		     if (ins->vibType == 1) autoVibVal = (ch->eVibPos > 127) ? 64 : -64; // square
1649 		else if (ins->vibType == 2) autoVibVal = (((ch->eVibPos >> 1) + 64) & 127) - 64; // ramp up
1650 		else if (ins->vibType == 3) autoVibVal = ((-(ch->eVibPos >> 1) + 64) & 127) - 64; // ramp down
1651 		else autoVibVal = vibSineTab[ch->eVibPos]; // sine
1652 
1653 		autoVibVal <<= 2;
1654 		uint16_t tmpPeriod = (autoVibVal * (int16_t)autoVibAmp) >> 16;
1655 
1656 		tmpPeriod += ch->outPeriod;
1657 		if (tmpPeriod > MAX_FRQ-1)
1658 			tmpPeriod = 0; // yes, FT2 does this (!)
1659 
1660 #ifdef HAS_MIDI
1661 		if (midi.enable)
1662 			tmpPeriod -= ch->midiPitch;
1663 #endif
1664 
1665 		ch->finalPeriod = tmpPeriod;
1666 		ch->status |= IS_Period;
1667 	}
1668 	else
1669 	{
1670 		ch->finalPeriod = ch->outPeriod;
1671 
1672 #ifdef HAS_MIDI
1673 		if (midi.enable)
1674 		{
1675 			ch->finalPeriod -= ch->midiPitch;
1676 			ch->status |= IS_Period;
1677 		}
1678 #endif
1679 	}
1680 }
1681 
1682 // for arpeggio and portamento (semitone-slide mode)
relocateTon(uint16_t period,uint8_t arpNote,channel_t * ch)1683 static uint16_t relocateTon(uint16_t period, uint8_t arpNote, channel_t *ch)
1684 {
1685 	int32_t tmpPeriod;
1686 
1687 	const int32_t fineTune = ((int8_t)ch->finetune >> 3) + 16;
1688 
1689 	/* FT2 bug, should've been 10*12*16. Notes above B-7 (95) will have issues.
1690 	** You can only achieve such high notes by having a high relative note setting.
1691 	*/
1692 	int32_t hiPeriod = 8*12*16;
1693 
1694 	int32_t loPeriod = 0;
1695 
1696 	for (int32_t i = 0; i < 8; i++)
1697 	{
1698 		tmpPeriod = (((loPeriod + hiPeriod) >> 1) & ~15) + fineTune;
1699 
1700 		int32_t lookUp = tmpPeriod - 8;
1701 		if (lookUp < 0)
1702 			lookUp = 0; // safety fix (C-0 w/ f.tune <= -65). This seems to result in 0 in FT2 (TODO: verify)
1703 
1704 		if (period >= note2Period[lookUp])
1705 			hiPeriod = (tmpPeriod - fineTune) & ~15;
1706 		else
1707 			loPeriod = (tmpPeriod - fineTune) & ~15;
1708 	}
1709 
1710 	tmpPeriod = loPeriod + fineTune + (arpNote << 4);
1711 	if (tmpPeriod >= (8*12*16+15)-1) // FT2 bug, should've been 10*12*16+16 (also notice the +2 difference)
1712 		tmpPeriod = (8*12*16+16)-1;
1713 
1714 	return note2Period[tmpPeriod];
1715 }
1716 
vibrato2(channel_t * ch)1717 static void vibrato2(channel_t *ch)
1718 {
1719 	uint8_t tmpVib = (ch->vibPos >> 2) & 0x1F;
1720 
1721 	switch (ch->waveCtrl & 3)
1722 	{
1723 		// 0: sine
1724 		case 0: tmpVib = vibTab[tmpVib]; break;
1725 
1726 		// 1: ramp
1727 		case 1:
1728 		{
1729 			tmpVib <<= 3;
1730 			if ((int8_t)ch->vibPos < 0)
1731 				tmpVib = ~tmpVib;
1732 		}
1733 		break;
1734 
1735 		// 2/3: square
1736 		default: tmpVib = 255; break;
1737 	}
1738 
1739 	tmpVib = (tmpVib * ch->vibDepth) >> 5; // logical shift (unsigned calc.), not arithmetic shift
1740 
1741 	if ((int8_t)ch->vibPos < 0)
1742 		ch->outPeriod = ch->realPeriod - tmpVib;
1743 	else
1744 		ch->outPeriod = ch->realPeriod + tmpVib;
1745 
1746 	ch->status |= IS_Period;
1747 	ch->vibPos += ch->vibSpeed;
1748 }
1749 
arp(channel_t * ch,uint8_t param)1750 static void arp(channel_t *ch, uint8_t param)
1751 {
1752 	uint8_t note;
1753 
1754 	const uint8_t tick = arpTab[song.tick & 0xFF]; // non-FT2 protection (we have 248 extra overflow bytes in LUT, but not more!)
1755 	if (tick == 0)
1756 	{
1757 		ch->outPeriod = ch->realPeriod;
1758 	}
1759 	else
1760 	{
1761 		if (tick == 1)
1762 			note = param >> 4;
1763 		else
1764 			note = param & 0x0F; // tick 2
1765 
1766 		ch->outPeriod = relocateTon(ch->realPeriod, note, ch);
1767 	}
1768 
1769 	ch->status |= IS_Period;
1770 }
1771 
portaUp(channel_t * ch,uint8_t param)1772 static void portaUp(channel_t *ch, uint8_t param)
1773 {
1774 	if (param == 0)
1775 		param = ch->portaUpSpeed;
1776 
1777 	ch->portaUpSpeed = param;
1778 
1779 	ch->realPeriod -= param << 2;
1780 	if ((int16_t)ch->realPeriod < 1)
1781 		ch->realPeriod = 1;
1782 
1783 	ch->outPeriod = ch->realPeriod;
1784 	ch->status |= IS_Period;
1785 }
1786 
portaDown(channel_t * ch,uint8_t param)1787 static void portaDown(channel_t *ch, uint8_t param)
1788 {
1789 	if (param == 0)
1790 		param = ch->portaDownSpeed;
1791 
1792 	ch->portaDownSpeed = param;
1793 
1794 	ch->realPeriod += param << 2;
1795 	if ((int16_t)ch->realPeriod > MAX_FRQ-1) // FT2 bug, should've been unsigned comparison
1796 		ch->realPeriod = MAX_FRQ-1;
1797 
1798 	ch->outPeriod = ch->realPeriod;
1799 	ch->status |= IS_Period;
1800 }
1801 
tonePorta(channel_t * ch,uint8_t param)1802 static void tonePorta(channel_t *ch, uint8_t param)
1803 {
1804 	if (ch->portaDirection == 0)
1805 		return;
1806 
1807 	if (ch->portaDirection > 1)
1808 	{
1809 		ch->realPeriod -= ch->portaSpeed;
1810 		if ((int16_t)ch->realPeriod <= (int16_t)ch->wantPeriod)
1811 		{
1812 			ch->portaDirection = 1;
1813 			ch->realPeriod = ch->wantPeriod;
1814 		}
1815 	}
1816 	else
1817 	{
1818 		ch->realPeriod += ch->portaSpeed;
1819 		if (ch->realPeriod >= ch->wantPeriod)
1820 		{
1821 			ch->portaDirection = 1;
1822 			ch->realPeriod = ch->wantPeriod;
1823 		}
1824 	}
1825 
1826 	if (ch->glissFunk) // semitone-slide flag
1827 		ch->outPeriod = relocateTon(ch->realPeriod, 0, ch);
1828 	else
1829 		ch->outPeriod = ch->realPeriod;
1830 
1831 	ch->status |= IS_Period;
1832 
1833 	(void)param;
1834 }
1835 
vibrato(channel_t * ch,uint8_t param)1836 static void vibrato(channel_t *ch, uint8_t param)
1837 {
1838 	uint8_t tmp8;
1839 
1840 	if (param > 0)
1841 	{
1842 		tmp8 = param & 0x0F;
1843 		if (tmp8 > 0)
1844 			ch->vibDepth = tmp8;
1845 
1846 		tmp8 = (param & 0xF0) >> 2;
1847 		if (tmp8 > 0)
1848 			ch->vibSpeed = tmp8;
1849 	}
1850 
1851 	vibrato2(ch);
1852 }
1853 
tonePlusVol(channel_t * ch,uint8_t param)1854 static void tonePlusVol(channel_t *ch, uint8_t param)
1855 {
1856 	tonePorta(ch, 0); // the last parameter is actually not used in tonePorta()
1857 	volume(ch, param);
1858 
1859 	(void)param;
1860 }
1861 
vibratoPlusVol(channel_t * ch,uint8_t param)1862 static void vibratoPlusVol(channel_t *ch, uint8_t param)
1863 {
1864 	vibrato2(ch);
1865 	volume(ch, param);
1866 
1867 	(void)param;
1868 }
1869 
tremolo(channel_t * ch,uint8_t param)1870 static void tremolo(channel_t *ch, uint8_t param)
1871 {
1872 	uint8_t tmp8;
1873 	int16_t tremVol;
1874 
1875 	const uint8_t tmpEff = param;
1876 	if (tmpEff > 0)
1877 	{
1878 		tmp8 = tmpEff & 0x0F;
1879 		if (tmp8 > 0)
1880 			ch->tremDepth = tmp8;
1881 
1882 		tmp8 = (tmpEff & 0xF0) >> 2;
1883 		if (tmp8 > 0)
1884 			ch->tremSpeed = tmp8;
1885 	}
1886 
1887 	uint8_t tmpTrem = (ch->tremPos >> 2) & 0x1F;
1888 	switch ((ch->waveCtrl >> 4) & 3)
1889 	{
1890 		// 0: sine
1891 		case 0: tmpTrem = vibTab[tmpTrem]; break;
1892 
1893 		// 1: ramp
1894 		case 1:
1895 		{
1896 			tmpTrem <<= 3;
1897 			if ((int8_t)ch->vibPos < 0) // FT2 bug, should've been ch->tremPos
1898 				tmpTrem = ~tmpTrem;
1899 		}
1900 		break;
1901 
1902 		// 2/3: square
1903 		default: tmpTrem = 255; break;
1904 	}
1905 	tmpTrem = (tmpTrem * ch->tremDepth) >> 6; // logical shift (unsigned calc.), not arithmetic shift
1906 
1907 	if ((int8_t)ch->tremPos < 0)
1908 	{
1909 		tremVol = ch->realVol - tmpTrem;
1910 		if (tremVol < 0)
1911 			tremVol = 0;
1912 	}
1913 	else
1914 	{
1915 		tremVol = ch->realVol + tmpTrem;
1916 		if (tremVol > 64)
1917 			tremVol = 64;
1918 	}
1919 
1920 	ch->outVol = (uint8_t)tremVol;
1921 	ch->status |= IS_Vol;
1922 	ch->tremPos += ch->tremSpeed;
1923 }
1924 
volume(channel_t * ch,uint8_t param)1925 static void volume(channel_t *ch, uint8_t param) // volume slide
1926 {
1927 	if (param == 0)
1928 		param = ch->volSlideSpeed;
1929 
1930 	ch->volSlideSpeed = param;
1931 
1932 	uint8_t newVol = ch->realVol;
1933 	if ((param & 0xF0) == 0)
1934 	{
1935 		newVol -= param;
1936 		if ((int8_t)newVol < 0)
1937 			newVol = 0;
1938 	}
1939 	else
1940 	{
1941 		param >>= 4;
1942 
1943 		newVol += param;
1944 		if (newVol > 64)
1945 			newVol = 64;
1946 	}
1947 
1948 	ch->outVol = ch->realVol = newVol;
1949 	ch->status |= IS_Vol;
1950 }
1951 
globalVolSlide(channel_t * ch,uint8_t param)1952 static void globalVolSlide(channel_t *ch, uint8_t param)
1953 {
1954 	if (param == 0)
1955 		param = ch->globVolSlideSpeed;
1956 
1957 	ch->globVolSlideSpeed = param;
1958 
1959 	uint8_t newVol = (uint8_t)song.globalVolume;
1960 	if ((param & 0xF0) == 0)
1961 	{
1962 		newVol -= param;
1963 		if ((int8_t)newVol < 0)
1964 			newVol = 0;
1965 	}
1966 	else
1967 	{
1968 		param >>= 4;
1969 
1970 		newVol += param;
1971 		if (newVol > 64)
1972 			newVol = 64;
1973 	}
1974 
1975 	song.globalVolume = newVol;
1976 
1977 	channel_t *c = channel;
1978 	for (int32_t i = 0; i < song.numChannels; i++, c++) // update all voice volumes
1979 		c->status |= IS_Vol;
1980 }
1981 
keyOffCmd(channel_t * ch,uint8_t param)1982 static void keyOffCmd(channel_t *ch, uint8_t param)
1983 {
1984 	if ((uint8_t)(song.speed-song.tick) == (param & 31))
1985 		keyOff(ch);
1986 }
1987 
panningSlide(channel_t * ch,uint8_t param)1988 static void panningSlide(channel_t *ch, uint8_t param)
1989 {
1990 	if (param == 0)
1991 		param = ch->panningSlideSpeed;
1992 
1993 	ch->panningSlideSpeed = param;
1994 
1995 	int16_t newPan = (int16_t)ch->outPan;
1996 	if ((param & 0xF0) == 0)
1997 	{
1998 		newPan -= param;
1999 		if (newPan < 0)
2000 			newPan = 0;
2001 	}
2002 	else
2003 	{
2004 		param >>= 4;
2005 
2006 		newPan += param;
2007 		if (newPan > 255)
2008 			newPan = 255;
2009 	}
2010 
2011 	ch->outPan = (uint8_t)newPan;
2012 	ch->status |= IS_Pan;
2013 }
2014 
tremor(channel_t * ch,uint8_t param)2015 static void tremor(channel_t *ch, uint8_t param)
2016 {
2017 	if (param == 0)
2018 		param = ch->tremorSave;
2019 
2020 	ch->tremorSave = param;
2021 
2022 	uint8_t tremorSign = ch->tremorPos & 0x80;
2023 	uint8_t tremorData = ch->tremorPos & 0x7F;
2024 
2025 	tremorData--;
2026 	if ((int8_t)tremorData < 0)
2027 	{
2028 		if (tremorSign == 0x80)
2029 		{
2030 			tremorSign = 0x00;
2031 			tremorData = param & 0x0F;
2032 		}
2033 		else
2034 		{
2035 			tremorSign = 0x80;
2036 			tremorData = param >> 4;
2037 		}
2038 	}
2039 
2040 	ch->tremorPos = tremorSign | tremorData;
2041 	ch->outVol = (tremorSign == 0x80) ? ch->realVol : 0;
2042 	ch->status |= IS_Vol + IS_QuickVol;
2043 }
2044 
retrigNote(channel_t * ch,uint8_t param)2045 static void retrigNote(channel_t *ch, uint8_t param)
2046 {
2047 	if (param == 0) // E9x with a param of zero is handled in getNewNote()
2048 		return;
2049 
2050 	if ((song.speed-song.tick) % param == 0)
2051 	{
2052 		startTone(0, 0, 0, ch);
2053 		retrigEnvelopeVibrato(ch);
2054 	}
2055 }
2056 
noteCut(channel_t * ch,uint8_t param)2057 static void noteCut(channel_t *ch, uint8_t param)
2058 {
2059 	if ((uint8_t)(song.speed-song.tick) == param)
2060 	{
2061 		ch->outVol = ch->realVol = 0;
2062 		ch->status |= IS_Vol + IS_QuickVol;
2063 	}
2064 }
2065 
noteDelay(channel_t * ch,uint8_t param)2066 static void noteDelay(channel_t *ch, uint8_t param)
2067 {
2068 	if ((uint8_t)(song.speed-song.tick) == param)
2069 	{
2070 		startTone(ch->noteData & 0xFF, 0, 0, ch);
2071 
2072 		if ((ch->noteData & 0xFF00) > 0)
2073 			retrigVolume(ch);
2074 
2075 		retrigEnvelopeVibrato(ch);
2076 
2077 		if (ch->volColumnVol >= 0x10 && ch->volColumnVol <= 0x50)
2078 		{
2079 			ch->outVol = ch->volColumnVol - 16;
2080 			ch->realVol = ch->outVol;
2081 		}
2082 		else if (ch->volColumnVol >= 0xC0 && ch->volColumnVol <= 0xCF)
2083 		{
2084 			ch->outPan = (ch->volColumnVol & 0x0F) << 4;
2085 		}
2086 	}
2087 }
2088 
2089 static const efxRoutine EJumpTab_TickNonZero[16] =
2090 {
2091 	dummy, // 0
2092 	dummy, // 1
2093 	dummy, // 2
2094 	dummy, // 3
2095 	dummy, // 4
2096 	dummy, // 5
2097 	dummy, // 6
2098 	dummy, // 7
2099 	dummy, // 8
2100 	retrigNote, // 9
2101 	dummy, // A
2102 	dummy, // B
2103 	noteCut, // C
2104 	noteDelay, // D
2105 	dummy, // E
2106 	dummy // F
2107 };
2108 
E_Effects_TickNonZero(channel_t * ch,uint8_t param)2109 static void E_Effects_TickNonZero(channel_t *ch, uint8_t param)
2110 {
2111 	EJumpTab_TickNonZero[param >> 4](ch, param & 0xF);
2112 }
2113 
2114 static const efxRoutine JumpTab_TickNonZero[36] =
2115 {
2116 	arp, // 0
2117 	portaUp, // 1
2118 	portaDown, // 2
2119 	tonePorta, // 3
2120 	vibrato, // 4
2121 	tonePlusVol, // 5
2122 	vibratoPlusVol, // 6
2123 	tremolo, // 7
2124 	dummy, // 8
2125 	dummy, // 9
2126 	volume, // A
2127 	dummy, // B
2128 	dummy, // C
2129 	dummy, // D
2130 	E_Effects_TickNonZero, // E
2131 	dummy, // F
2132 	dummy, // G
2133 	globalVolSlide, // H
2134 	dummy, // I
2135 	dummy, // J
2136 	keyOffCmd, // K
2137 	dummy, // L
2138 	dummy, // M
2139 	dummy, // N
2140 	dummy, // O
2141 	panningSlide, // P
2142 	dummy, // Q
2143 	doMultiRetrig, // R
2144 	dummy, // S
2145 	tremor, // T
2146 	dummy, // U
2147 	dummy, // V
2148 	dummy, // W
2149 	dummy, // X
2150 	dummy, // Y
2151 	dummy  // Z
2152 };
2153 
handleEffects_TickNonZero(channel_t * ch)2154 static void handleEffects_TickNonZero(channel_t *ch)
2155 {
2156 	if (ch->channelOff)
2157 		return; // muted
2158 
2159 	// volume column effects
2160 	VJumpTab_TickNonZero[ch->volColumnVol >> 4](ch);
2161 
2162 	// normal effects
2163 	if ((ch->efx == 0 && ch->efxData == 0) || ch->efx > 35)
2164 		return; // no effect
2165 
2166 	JumpTab_TickNonZero[ch->efx](ch, ch->efxData);
2167 }
2168 
getNextPos(void)2169 static void getNextPos(void)
2170 {
2171 	if (song.tick != 1)
2172 		return;
2173 
2174 	song.row++;
2175 
2176 	if (song.pattDelTime > 0)
2177 	{
2178 		song.pattDelTime2 = song.pattDelTime;
2179 		song.pattDelTime = 0;
2180 	}
2181 
2182 	if (song.pattDelTime2 > 0)
2183 	{
2184 		song.pattDelTime2--;
2185 		if (song.pattDelTime2 > 0)
2186 			song.row--;
2187 	}
2188 
2189 	if (song.pBreakFlag)
2190 	{
2191 		song.pBreakFlag = false;
2192 		song.row = song.pBreakPos;
2193 	}
2194 
2195 	if (song.row >= song.currNumRows || song.posJumpFlag)
2196 	{
2197 		song.row = song.pBreakPos;
2198 		song.pBreakPos = 0;
2199 		song.posJumpFlag = false;
2200 
2201 		if (playMode != PLAYMODE_PATT && playMode != PLAYMODE_RECPATT)
2202 		{
2203 			if (bxxOverflow)
2204 			{
2205 				song.songPos = 0;
2206 				bxxOverflow = false;
2207 			}
2208 			else if (++song.songPos >= song.songLength)
2209 			{
2210 				editor.wavReachedEndFlag = true;
2211 				song.songPos = song.songLoopStart;
2212 			}
2213 
2214 			assert(song.songPos <= 255);
2215 			song.pattNum = song.orders[song.songPos & 0xFF];
2216 			song.currNumRows = patternNumRows[song.pattNum & 0xFF];
2217 		}
2218 	}
2219 }
2220 
pauseMusic(void)2221 void pauseMusic(void) // stops reading pattern data
2222 {
2223 	musicPaused = true;
2224 	while (replayerBusy);
2225 }
2226 
resumeMusic(void)2227 void resumeMusic(void) // starts reading pattern data
2228 {
2229 	musicPaused = false;
2230 }
2231 
2232 
tickReplayer(void)2233 void tickReplayer(void) // periodically called from audio callback
2234 {
2235 	int32_t i;
2236 	channel_t *ch;
2237 
2238 	if (musicPaused || !songPlaying)
2239 	{
2240 		ch = channel;
2241 		for (i = 0; i < song.numChannels; i++, ch++)
2242 			updateChannel(ch);
2243 
2244 		return;
2245 	}
2246 
2247 	// for song playback counter (hh:mm:ss)
2248 	if (song.BPM >= MIN_BPM && song.BPM <= MAX_BPM)
2249 		song.musicTime64 += musicTimeTab64[song.BPM-MIN_BPM];
2250 
2251 	bool tickZero = false;
2252 	if (--song.tick == 0)
2253 	{
2254 		song.tick = song.speed;
2255 		tickZero = true;
2256 	}
2257 
2258 	song.curReplayerTick = (uint8_t)song.tick; // for audio/video syncing (and recording)
2259 
2260 	const bool readNewNote = tickZero && (song.pattDelTime2 == 0);
2261 	if (readNewNote)
2262 	{
2263 		// set audio/video syncing variables
2264 		song.curReplayerRow = (uint8_t)song.row;
2265 		song.curReplayerPattNum = (uint8_t)song.pattNum;
2266 		song.curReplayerSongPos = (uint8_t)song.songPos;
2267 		// ----------------------------------------------
2268 
2269 		const note_t *p = nilPatternLine;
2270 		if (pattern[song.pattNum] != NULL)
2271 			p = &pattern[song.pattNum][song.row * MAX_CHANNELS];
2272 
2273 		ch = channel;
2274 		for (i = 0; i < song.numChannels; i++, ch++, p++)
2275 		{
2276 			getNewNote(ch, p);
2277 			updateChannel(ch);
2278 		}
2279 	}
2280 	else
2281 	{
2282 		ch = channel;
2283 		for (i = 0; i < song.numChannels; i++, ch++)
2284 		{
2285 			handleEffects_TickNonZero(ch);
2286 			updateChannel(ch);
2287 		}
2288 	}
2289 
2290 	getNextPos();
2291 }
2292 
resetMusic(void)2293 void resetMusic(void)
2294 {
2295 	const bool audioWasntLocked = !audio.locked;
2296 	if (audioWasntLocked)
2297 		lockAudio();
2298 
2299 	song.tick = 1;
2300 	stopVoices();
2301 
2302 	if (audioWasntLocked)
2303 		unlockAudio();
2304 
2305 	setPos(0, 0, false);
2306 
2307 	if (!songPlaying)
2308 	{
2309 		setScrollBarEnd(SB_POS_ED, (song.songLength - 1) + 5);
2310 		setScrollBarPos(SB_POS_ED, 0, false);
2311 	}
2312 }
2313 
setPos(int16_t songPos,int16_t row,bool resetTimer)2314 void setPos(int16_t songPos, int16_t row, bool resetTimer)
2315 {
2316 	const bool audioWasntLocked = !audio.locked;
2317 	if (audioWasntLocked)
2318 		lockAudio();
2319 
2320 	if (songPos > -1)
2321 	{
2322 		song.songPos = songPos;
2323 		if (song.songLength > 0 && song.songPos >= song.songLength)
2324 			song.songPos = song.songLength - 1;
2325 
2326 		song.pattNum = song.orders[song.songPos];
2327 		assert(song.pattNum < MAX_PATTERNS);
2328 		song.currNumRows = patternNumRows[song.pattNum];
2329 
2330 		checkMarkLimits(); // non-FT2 safety
2331 	}
2332 
2333 	if (row > -1)
2334 	{
2335 		song.row = row;
2336 		if (song.row >= song.currNumRows)
2337 			song.row = song.currNumRows-1;
2338 	}
2339 
2340 	// if not playing, update local position variables
2341 	if (!songPlaying)
2342 	{
2343 		if (row > -1)
2344 		{
2345 			editor.row = (uint8_t)row;
2346 			ui.updatePatternEditor = true;
2347 		}
2348 
2349 		if (songPos > -1)
2350 		{
2351 			editor.editPattern = (uint8_t)song.pattNum;
2352 			editor.songPos = song.songPos;
2353 			ui.updatePosSections = true;
2354 		}
2355 	}
2356 
2357 	if (resetTimer)
2358 		song.tick = 1;
2359 
2360 	if (audioWasntLocked)
2361 		unlockAudio();
2362 }
2363 
delta2Samp(int8_t * p,int32_t length,uint8_t smpFlags)2364 void delta2Samp(int8_t *p, int32_t length, uint8_t smpFlags)
2365 {
2366 	bool sample16Bit = !!(smpFlags & SAMPLE_16BIT);
2367 	bool stereo = !!(smpFlags & SAMPLE_STEREO);
2368 
2369 	if (stereo)
2370 	{
2371 		length >>= 1;
2372 
2373 		if (sample16Bit)
2374 		{
2375 			int16_t *p16L = (int16_t *)p;
2376 			int16_t *p16R = (int16_t *)p + length;
2377 
2378 			int16_t olds16L = 0;
2379 			int16_t olds16R = 0;
2380 
2381 			for (int32_t i = 0; i < length; i++)
2382 			{
2383 				const int16_t news16L = p16L[i] + olds16L;
2384 				p16L[i] = news16L;
2385 				olds16L = news16L;
2386 
2387 				const int16_t news16R = p16R[i] + olds16R;
2388 				p16R[i] = news16R;
2389 				olds16R = news16R;
2390 
2391 				p16L[i] = (int16_t)((olds16L + olds16R) >> 1);
2392 			}
2393 		}
2394 		else // 8-bit
2395 		{
2396 			int8_t *p8L = (int8_t *)p;
2397 			int8_t *p8R = (int8_t *)p + length;
2398 			int8_t olds8L = 0;
2399 			int8_t olds8R = 0;
2400 
2401 			for (int32_t i = 0; i < length; i++)
2402 			{
2403 				const int8_t news8L = p8L[i] + olds8L;
2404 				p8L[i] = news8L;
2405 				olds8L = news8L;
2406 
2407 				const int8_t news8R = p8R[i] + olds8R;
2408 				p8R[i] = news8R;
2409 				olds8R = news8R;
2410 
2411 				p8L[i] = (int8_t)((olds8L + olds8R) >> 1);
2412 			}
2413 		}
2414 	}
2415 	else // mono (normal sample)
2416 	{
2417 		if (sample16Bit)
2418 		{
2419 			int16_t *p16 = (int16_t *)p;
2420 
2421 			int16_t olds16L = 0;
2422 			for (int32_t i = 0; i < length; i++)
2423 			{
2424 				const int16_t news16 = p16[i] + olds16L;
2425 				p16[i] = news16;
2426 				olds16L = news16;
2427 			}
2428 		}
2429 		else // 8-bit
2430 		{
2431 			int8_t *p8 = (int8_t *)p;
2432 
2433 			int8_t olds8L = 0;
2434 			for (int32_t i = 0; i < length; i++)
2435 			{
2436 				const int8_t news8 = p8[i] + olds8L;
2437 				p8[i] = news8;
2438 				olds8L = news8;
2439 			}
2440 		}
2441 	}
2442 }
2443 
samp2Delta(int8_t * p,int32_t length,uint8_t smpFlags)2444 void samp2Delta(int8_t *p, int32_t length, uint8_t smpFlags)
2445 {
2446 	if (smpFlags & SAMPLE_16BIT)
2447 	{
2448 		int16_t *p16 = (int16_t *)p;
2449 
2450 		int16_t newS16 = 0;
2451 		for (int32_t i = 0; i < length; i++)
2452 		{
2453 			const int16_t oldS16 = p16[i];
2454 			p16[i] -= newS16;
2455 			newS16 = oldS16;
2456 		}
2457 	}
2458 	else // 8-bit
2459 	{
2460 		int8_t *p8 = (int8_t *)p;
2461 
2462 		int8_t newS8 = 0;
2463 		for (int32_t i = 0; i < length; i++)
2464 		{
2465 			const int8_t oldS8 = p8[i];
2466 			p8[i] -= newS8;
2467 			newS8 = oldS8;
2468 		}
2469 	}
2470 }
2471 
allocateInstr(int16_t insNum)2472 bool allocateInstr(int16_t insNum)
2473 {
2474 	if (instr[insNum] != NULL)
2475 		return false; // already allocated
2476 
2477 	instr_t *p = (instr_t *)malloc(sizeof (instr_t));
2478 	if (p == NULL)
2479 		return false;
2480 
2481 	memset(p, 0, sizeof (instr_t));
2482 	for (int32_t i = 0; i < MAX_SMP_PER_INST; i++)
2483 	{
2484 		p->smp[i].panning = 128;
2485 		p->smp[i].volume = 64;
2486 	}
2487 
2488 	setStdEnvelope(p, 0, 3);
2489 
2490 	const bool audioWasntLocked = !audio.locked;
2491 	if (audioWasntLocked)
2492 		lockAudio();
2493 
2494 	instr[insNum] = p;
2495 
2496 	if (audioWasntLocked)
2497 		unlockAudio();
2498 
2499 	return true;
2500 }
2501 
freeInstr(int32_t insNum)2502 void freeInstr(int32_t insNum)
2503 {
2504 	if (instr[insNum] == NULL)
2505 		return; // not allocated
2506 
2507 	pauseAudio(); // channel instrument pointers are now cleared
2508 
2509 	sample_t *s = instr[insNum]->smp;
2510 	for (int32_t i = 0; i < MAX_SMP_PER_INST; i++, s++) // free sample data
2511 		freeSmpData(s);
2512 
2513 	free(instr[insNum]);
2514 	instr[insNum] = NULL;
2515 
2516 	resumeAudio();
2517 }
2518 
freeAllInstr(void)2519 void freeAllInstr(void)
2520 {
2521 	pauseAudio(); // channel instrument pointers are now cleared
2522 	for (int32_t i = 1; i <= MAX_INST; i++)
2523 	{
2524 		if (instr[i] != NULL)
2525 		{
2526 			sample_t *s = instr[i]->smp;
2527 			for (int32_t j = 0; j < MAX_SMP_PER_INST; j++, s++) // free sample data
2528 				freeSmpData(s);
2529 
2530 			free(instr[i]);
2531 			instr[i] = NULL;
2532 		}
2533 	}
2534 	resumeAudio();
2535 }
2536 
freeSample(int16_t insNum,int16_t smpNum)2537 void freeSample(int16_t insNum, int16_t smpNum)
2538 {
2539 	if (instr[insNum] == NULL)
2540 		return; // instrument not allocated
2541 
2542 	pauseAudio(); // voice sample pointers are now cleared
2543 
2544 	sample_t *s = &instr[insNum]->smp[smpNum];
2545 	freeSmpData(s);
2546 
2547 	memset(s, 0, sizeof (sample_t));
2548 	s->panning = 128;
2549 	s->volume = 64;
2550 
2551 	resumeAudio();
2552 }
2553 
freeAllPatterns(void)2554 void freeAllPatterns(void)
2555 {
2556 	pauseAudio();
2557 	for (int32_t i = 0; i < MAX_PATTERNS; i++)
2558 	{
2559 		if (pattern[i] != NULL)
2560 		{
2561 			free(pattern[i]);
2562 			pattern[i] = NULL;
2563 		}
2564 	}
2565 	resumeAudio();
2566 }
2567 
setStdEnvelope(instr_t * ins,int16_t i,uint8_t type)2568 void setStdEnvelope(instr_t *ins, int16_t i, uint8_t type)
2569 {
2570 	if (ins == NULL)
2571 		return;
2572 
2573 	pauseMusic();
2574 
2575 	if (type & 1)
2576 	{
2577 		memcpy(ins->volEnvPoints, config.stdEnvPoints[i][0], 2*2*12);
2578 		ins->volEnvLength = (uint8_t)config.stdVolEnvLength[i];
2579 		ins->volEnvSustain = (uint8_t)config.stdVolEnvSustain[i];
2580 		ins->volEnvLoopStart = (uint8_t)config.stdVolEnvLoopStart[i];
2581 		ins->volEnvLoopEnd = (uint8_t)config.stdVolEnvLoopEnd[i];
2582 		ins->fadeout = config.stdFadeout[i];
2583 		ins->vibRate = (uint8_t)config.stdVibRate[i];
2584 		ins->vibDepth = (uint8_t)config.stdVibDepth[i];
2585 		ins->vibSweep = (uint8_t)config.stdVibSweep[i];
2586 		ins->vibType = (uint8_t)config.stdVibType[i];
2587 		ins->volEnvFlags = (uint8_t)config.stdVolEnvFlags[i];
2588 	}
2589 
2590 	if (type & 2)
2591 	{
2592 		memcpy(ins->panEnvPoints, config.stdEnvPoints[i][1], 2*2*12);
2593 		ins->panEnvLength = (uint8_t)config.stdPanEnvLength[0];
2594 		ins->panEnvSustain = (uint8_t)config.stdPanEnvSustain[0];
2595 		ins->panEnvLoopStart = (uint8_t)config.stdPanEnvLoopStart[0];
2596 		ins->panEnvLoopEnd = (uint8_t)config.stdPanEnvLoopEnd[0];
2597 		ins->panEnvFlags  = (uint8_t)config.stdPanEnvFlags[0];
2598 	}
2599 
2600 	resumeMusic();
2601 }
2602 
setNoEnvelope(instr_t * ins)2603 void setNoEnvelope(instr_t *ins)
2604 {
2605 	if (ins == NULL)
2606 		return;
2607 
2608 	pauseMusic();
2609 
2610 	memcpy(ins->volEnvPoints, config.stdEnvPoints[0][0], 2*2*12);
2611 	ins->volEnvLength = (uint8_t)config.stdVolEnvLength[0];
2612 	ins->volEnvSustain = (uint8_t)config.stdVolEnvSustain[0];
2613 	ins->volEnvLoopStart = (uint8_t)config.stdVolEnvLoopStart[0];
2614 	ins->volEnvLoopEnd = (uint8_t)config.stdVolEnvLoopEnd[0];
2615 	ins->volEnvFlags = 0;
2616 
2617 	memcpy(ins->panEnvPoints, config.stdEnvPoints[0][1], 2*2*12);
2618 	ins->panEnvLength = (uint8_t)config.stdPanEnvLength[0];
2619 	ins->panEnvSustain = (uint8_t)config.stdPanEnvSustain[0];
2620 	ins->panEnvLoopStart = (uint8_t)config.stdPanEnvLoopStart[0];
2621 	ins->panEnvLoopEnd = (uint8_t)config.stdPanEnvLoopEnd[0];
2622 	ins->panEnvFlags = 0;
2623 
2624 	ins->fadeout = 0;
2625 	ins->vibRate = 0;
2626 	ins->vibDepth = 0;
2627 	ins->vibSweep = 0;
2628 	ins->vibType = 0;
2629 
2630 	resumeMusic();
2631 }
2632 
patternEmpty(uint16_t pattNum)2633 bool patternEmpty(uint16_t pattNum)
2634 {
2635 	if (pattern[pattNum] == NULL)
2636 		return true;
2637 
2638 	const uint8_t *scanPtr = (const uint8_t *)pattern[pattNum];
2639 	const uint32_t scanLen = patternNumRows[pattNum] * TRACK_WIDTH;
2640 
2641 	for (uint32_t i = 0; i < scanLen; i++)
2642 	{
2643 		if (scanPtr[i] != 0)
2644 			return false;
2645 	}
2646 
2647 	return true;
2648 }
2649 
updateChanNums(void)2650 void updateChanNums(void)
2651 {
2652 	assert(!(song.numChannels & 1));
2653 
2654 	const int32_t maxChannelsShown = getMaxVisibleChannels();
2655 
2656 	int32_t channelsShown = song.numChannels;
2657 	if (channelsShown > maxChannelsShown)
2658 		channelsShown = maxChannelsShown;
2659 
2660 	ui.numChannelsShown = (uint8_t)channelsShown;
2661 	ui.pattChanScrollShown = (song.numChannels > maxChannelsShown);
2662 
2663 	if (ui.patternEditorShown)
2664 	{
2665 		if (ui.channelOffset > song.numChannels-ui.numChannelsShown)
2666 			setScrollBarPos(SB_CHAN_SCROLL, song.numChannels - ui.numChannelsShown, true);
2667 	}
2668 
2669 	if (ui.pattChanScrollShown)
2670 	{
2671 		if (ui.patternEditorShown)
2672 		{
2673 			showScrollBar(SB_CHAN_SCROLL);
2674 			showPushButton(PB_CHAN_SCROLL_LEFT);
2675 			showPushButton(PB_CHAN_SCROLL_RIGHT);
2676 		}
2677 
2678 		setScrollBarEnd(SB_CHAN_SCROLL, song.numChannels);
2679 		setScrollBarPageLength(SB_CHAN_SCROLL, ui.numChannelsShown);
2680 	}
2681 	else
2682 	{
2683 		hideScrollBar(SB_CHAN_SCROLL);
2684 		hidePushButton(PB_CHAN_SCROLL_LEFT);
2685 		hidePushButton(PB_CHAN_SCROLL_RIGHT);
2686 
2687 		setScrollBarPos(SB_CHAN_SCROLL, 0, false);
2688 
2689 		ui.channelOffset = 0;
2690 	}
2691 
2692 	if (cursor.ch >= ui.channelOffset+ui.numChannelsShown)
2693 		cursor.ch = ui.channelOffset+ui.numChannelsShown - 1;
2694 }
2695 
conv8BitSample(int8_t * p,int32_t length,bool stereo)2696 void conv8BitSample(int8_t *p, int32_t length, bool stereo) // changes sample sign
2697 {
2698 	if (stereo)
2699 	{
2700 		length >>= 1;
2701 
2702 		int8_t *p2 = &p[length];
2703 		for (int32_t i = 0; i < length; i++)
2704 		{
2705 			const int8_t l = p[i] ^ 0x80;
2706 			const int8_t r = p2[i] ^ 0x80;
2707 
2708 			p[i] = (int8_t)((l + r) >> 1);
2709 		}
2710 	}
2711 	else
2712 	{
2713 		for (int32_t i = 0; i < length; i++)
2714 			p[i] ^= 0x80;
2715 	}
2716 }
2717 
conv16BitSample(int8_t * p,int32_t length,bool stereo)2718 void conv16BitSample(int8_t *p, int32_t length, bool stereo) // changes sample sign
2719 {
2720 	int16_t *p16_1 = (int16_t *)p;
2721 
2722 	if (stereo)
2723 	{
2724 		length >>= 1;
2725 
2726 		int16_t *p16_2 = (int16_t *)p + length;
2727 		for (int32_t i = 0; i < length; i++)
2728 		{
2729 			const int16_t l = p16_1[i] ^ 0x8000;
2730 			const int16_t r = p16_2[i] ^ 0x8000;
2731 
2732 			p16_1[i] = (int16_t)((l + r) >> 1);
2733 		}
2734 	}
2735 	else
2736 	{
2737 		for (int32_t i = 0; i < length; i++)
2738 			p16_1[i] ^= 0x8000;
2739 	}
2740 }
2741 
closeReplayer(void)2742 void closeReplayer(void)
2743 {
2744 	freeAllInstr();
2745 	freeAllPatterns();
2746 
2747 	// free reserved instruments
2748 
2749 	if (instr[0] != NULL)
2750 	{
2751 		free(instr[0]);
2752 		instr[0] = NULL;
2753 	}
2754 
2755 	if (instr[130] != NULL)
2756 	{
2757 		free(instr[130]);
2758 		instr[130] = NULL;
2759 	}
2760 
2761 	if (instr[131] != NULL)
2762 	{
2763 		free(instr[131]);
2764 		instr[131] = NULL;
2765 	}
2766 
2767 	freeWindowedSincTables();
2768 }
2769 
setupReplayer(void)2770 bool setupReplayer(void)
2771 {
2772 	for (int32_t i = 0; i < MAX_PATTERNS; i++)
2773 		patternNumRows[i] = 64;
2774 
2775 	playMode = PLAYMODE_IDLE;
2776 	songPlaying = false;
2777 
2778 	// unmute all channels (must be done before resetChannels() call)
2779 	for (int32_t i = 0; i < MAX_CHANNELS; i++)
2780 		editor.chnMode[i] = 1;
2781 
2782 	resetChannels();
2783 
2784 	song.songLength = 1;
2785 	song.numChannels = 8;
2786 	editor.BPM = song.BPM = 125;
2787 	editor.speed = song.initialSpeed = song.speed = 6;
2788 	editor.globalVolume = song.globalVolume = 64;
2789 	audio.linearPeriodsFlag = true;
2790 	note2Period = linearPeriods;
2791 
2792 	if (!calcWindowedSincTables())
2793 	{
2794 		showErrorMsgBox("Not enough memory!");
2795 		return false;
2796 	}
2797 
2798 	calcPanningTable();
2799 
2800 	setPos(0, 0, true);
2801 
2802 	if (!allocateInstr(0))
2803 	{
2804 		showErrorMsgBox("Not enough memory!");
2805 		return false;
2806 	}
2807 	instr[0]->smp[0].volume = 0;
2808 
2809 	if (!allocateInstr(130))
2810 	{
2811 		showErrorMsgBox("Not enough memory!");
2812 		return false;
2813 	}
2814 	memset(instr[130], 0, sizeof (instr_t));
2815 
2816 	if (!allocateInstr(131)) // Instr. Ed. display instrument for unallocated/empty instruments
2817 	{
2818 		showErrorMsgBox("Not enough memory!");
2819 		return false;
2820 	}
2821 
2822 	memset(instr[131], 0, sizeof (instr_t));
2823 	for (int32_t i = 0; i < 16; i++)
2824 		instr[131]->smp[i].panning = 128;
2825 
2826 	editor.tmpPattern = 65535; // pattern editor update/redraw kludge
2827 	return true;
2828 }
2829 
startPlaying(int8_t mode,int16_t row)2830 void startPlaying(int8_t mode, int16_t row)
2831 {
2832 	lockMixerCallback();
2833 
2834 	assert(mode != PLAYMODE_IDLE && mode != PLAYMODE_EDIT);
2835 	if (mode == PLAYMODE_PATT || mode == PLAYMODE_RECPATT)
2836 		setPos(-1, row, true);
2837 	else
2838 		setPos(editor.songPos, row, true);
2839 
2840 	playMode = mode;
2841 	songPlaying = true;
2842 
2843 	resetReplayerState();
2844 	resetPlaybackTime();
2845 
2846 	// non-FT2 fix: If song speed was 0, set it back to initial speed on play
2847 	if (song.speed == 0)
2848 		song.speed = song.initialSpeed;
2849 
2850 	audio.tickSampleCounter64 = 0; // zero tick sample counter so that it will instantly initiate a tick
2851 
2852 	unlockMixerCallback();
2853 
2854 	ui.updatePosSections = true;
2855 	ui.updatePatternEditor = true;
2856 }
2857 
stopPlaying(void)2858 void stopPlaying(void)
2859 {
2860 	bool songWasPlaying = songPlaying;
2861 	playMode = PLAYMODE_IDLE;
2862 	songPlaying = false;
2863 
2864 	if (config.killNotesOnStopPlay)
2865 	{
2866 		// safely kills all voices
2867 		lockMixerCallback();
2868 		unlockMixerCallback();
2869 	}
2870 	else
2871 	{
2872 		for (uint8_t i = 0; i < MAX_CHANNELS; i++)
2873 			playTone(i, 0, NOTE_OFF, -1, 0, 0);
2874 	}
2875 
2876 	// if song was playing, update local row (fixes certain glitches)
2877 	if (songWasPlaying)
2878 		editor.row = song.row;
2879 
2880 #ifdef HAS_MIDI
2881 	midi.currMIDIVibDepth = 0;
2882 	midi.currMIDIPitch = 0;
2883 #endif
2884 
2885 	memset(editor.keyOnTab, 0, sizeof (editor.keyOnTab));
2886 
2887 	// kludge to prevent UI from being out of sync with replayer vars on stop
2888 	song.songPos = editor.songPos;
2889 	song.row = editor.row;
2890 	song.pattNum = editor.editPattern;
2891 
2892 	ui.updatePosSections = true;
2893 	ui.updatePatternEditor = true;
2894 
2895 	// certain non-FT2 fixes
2896 	song.tick = editor.tick = 1;
2897 	song.globalVolume = editor.globalVolume = 64;
2898 	ui.drawGlobVolFlag = true;
2899 }
2900 
2901 // from keyboard/smp. ed.
playTone(uint8_t chNum,uint8_t insNum,uint8_t note,int8_t vol,uint16_t midiVibDepth,uint16_t midiPitch)2902 void playTone(uint8_t chNum, uint8_t insNum, uint8_t note, int8_t vol, uint16_t midiVibDepth, uint16_t midiPitch)
2903 {
2904 	instr_t *ins = instr[insNum];
2905 	if (ins == NULL)
2906 		return;
2907 
2908 	assert(chNum < MAX_CHANNELS && insNum <= MAX_INST && note <= NOTE_OFF);
2909 	channel_t *ch = &channel[chNum];
2910 
2911 	// FT2 bugfix: Don't play tone if certain requirements are not met
2912 	if (note != NOTE_OFF)
2913 	{
2914 		if (note == 0 || note > 96)
2915 			return;
2916 
2917 		sample_t *s = &ins->smp[ins->note2SampleLUT[note-1] & 0xF];
2918 
2919 		int16_t finalNote = (int16_t)note + s->relativeNote;
2920 		if (s->dataPtr == NULL || s->length == 0 || finalNote <= 0 || finalNote >= 12*10)
2921 			return;
2922 	}
2923 	// -------------------
2924 
2925 	lockAudio();
2926 
2927 	if (insNum != 0 && note != NOTE_OFF)
2928 	{
2929 		ch->noteData = (insNum << 8) | (ch->noteData & 0xFF);
2930 		ch->instrNum = insNum;
2931 	}
2932 
2933 	ch->noteData = (ch->noteData & 0xFF00) | note;
2934 	ch->efx = 0;
2935 	ch->efxData = 0;
2936 
2937 	startTone(note, 0, 0, ch);
2938 
2939 	if (note != NOTE_OFF)
2940 	{
2941 		retrigVolume(ch);
2942 		retrigEnvelopeVibrato(ch);
2943 
2944 		if (vol != -1) // if jamming note keys, vol -1 = use sample's volume
2945 		{
2946 			ch->realVol = vol;
2947 			ch->outVol = vol;
2948 			ch->oldVol = vol;
2949 		}
2950 	}
2951 
2952 	ch->midiVibDepth = midiVibDepth;
2953 	ch->midiPitch = midiPitch;
2954 
2955 	updateChannel(ch);
2956 
2957 	unlockAudio();
2958 }
2959 
2960 // smp. ed.
playSample(uint8_t chNum,uint8_t insNum,uint8_t smpNum,uint8_t note,uint16_t midiVibDepth,uint16_t midiPitch)2961 void playSample(uint8_t chNum, uint8_t insNum, uint8_t smpNum, uint8_t note, uint16_t midiVibDepth, uint16_t midiPitch)
2962 {
2963 	if (instr[insNum] == NULL)
2964 		return;
2965 
2966 	// for sampling playback line in Smp. Ed.
2967 	lastChInstr[chNum].instrNum = 255;
2968 	lastChInstr[chNum].smpNum = 255;
2969 	editor.curPlayInstr = 255;
2970 	editor.curPlaySmp = 255;
2971 
2972 	assert(chNum < MAX_CHANNELS && insNum <= MAX_INST && smpNum < MAX_SMP_PER_INST && note <= NOTE_OFF);
2973 	channel_t *ch = &channel[chNum];
2974 
2975 	memcpy(&instr[130]->smp[0], &instr[insNum]->smp[smpNum], sizeof (sample_t));
2976 
2977 	uint8_t vol = instr[insNum]->smp[smpNum].volume;
2978 
2979 	lockAudio();
2980 
2981 	ch->instrNum = 130;
2982 	ch->noteData = (ch->instrNum << 8) | note;
2983 	ch->efx = 0;
2984 
2985 	startTone(note, 0, 0, ch);
2986 
2987 	if (note != NOTE_OFF)
2988 	{
2989 		retrigVolume(ch);
2990 		retrigEnvelopeVibrato(ch);
2991 
2992 		ch->realVol = vol;
2993 		ch->outVol = vol;
2994 		ch->oldVol = vol;
2995 	}
2996 
2997 	ch->midiVibDepth = midiVibDepth;
2998 	ch->midiPitch = midiPitch;
2999 
3000 	updateChannel(ch);
3001 
3002 	unlockAudio();
3003 
3004 	while (ch->status & IS_Trigger); // wait for sample to latch in mixer
3005 
3006 	// for sampling playback line in Smp. Ed.
3007 	editor.curPlayInstr = editor.curInstr;
3008 	editor.curPlaySmp = editor.curSmp;
3009 }
3010 
3011 // smp. ed.
playRange(uint8_t chNum,uint8_t insNum,uint8_t smpNum,uint8_t note,uint16_t midiVibDepth,uint16_t midiPitch,int32_t smpOffset,int32_t length)3012 void playRange(uint8_t chNum, uint8_t insNum, uint8_t smpNum, uint8_t note, uint16_t midiVibDepth, uint16_t midiPitch, int32_t smpOffset, int32_t length)
3013 {
3014 	if (instr[insNum] == NULL)
3015 		return;
3016 
3017 	// for sampling playback line in Smp. Ed.
3018 	lastChInstr[chNum].instrNum = 255;
3019 	lastChInstr[chNum].smpNum = 255;
3020 	editor.curPlayInstr = 255;
3021 	editor.curPlaySmp = 255;
3022 
3023 	assert(chNum < MAX_CHANNELS && insNum <= MAX_INST && smpNum < MAX_SMP_PER_INST && note <= NOTE_OFF);
3024 
3025 	channel_t *ch = &channel[chNum];
3026 	sample_t *s = &instr[130]->smp[0];
3027 
3028 	memcpy(s, &instr[insNum]->smp[smpNum], sizeof (sample_t));
3029 
3030 	uint8_t vol = instr[insNum]->smp[smpNum].volume;
3031 
3032 	lockAudio();
3033 
3034 	s->length = smpOffset + length;
3035 	s->loopStart = 0;
3036 	s->loopLength = 0;
3037 	DISABLE_LOOP(s->flags); // disable loop on sample #129 (placeholder)
3038 
3039 	int32_t samplePlayOffset = smpOffset;
3040 
3041 	ch->instrNum = 130;
3042 	ch->noteData = (ch->instrNum << 8) | note;
3043 	ch->efx = 0;
3044 	ch->efxData = 0;
3045 
3046 	startTone(note, 0, 0, ch);
3047 
3048 	ch->smpStartPos = samplePlayOffset;
3049 
3050 	if (note != NOTE_OFF)
3051 	{
3052 		retrigVolume(ch);
3053 		retrigEnvelopeVibrato(ch);
3054 
3055 		ch->realVol = vol;
3056 		ch->outVol = vol;
3057 		ch->oldVol = vol;
3058 	}
3059 
3060 	ch->midiVibDepth = midiVibDepth;
3061 	ch->midiPitch = midiPitch;
3062 
3063 	updateChannel(ch);
3064 
3065 	unlockAudio();
3066 
3067 	while (ch->status & IS_Trigger); // wait for sample to latch in mixer
3068 
3069 	// for sampling playback line in Smp. Ed.
3070 	editor.curPlayInstr = editor.curInstr;
3071 	editor.curPlaySmp = editor.curSmp;
3072 }
3073 
stopVoices(void)3074 void stopVoices(void)
3075 {
3076 	const bool audioWasntLocked = !audio.locked;
3077 	if (audioWasntLocked)
3078 		lockAudio();
3079 
3080 	channel_t *ch = channel;
3081 	for (int32_t i = 0; i < MAX_CHANNELS; i++, ch++)
3082 	{
3083 		lastChInstr[i].smpNum = 255;
3084 		lastChInstr[i].instrNum = 255;
3085 
3086 		ch->noteData = 0;
3087 		ch->relativeNote = 0;
3088 		ch->smpNum = 0;
3089 		ch->smpPtr = NULL;
3090 		ch->instrNum = 0;
3091 		ch->instrPtr = instr[0]; // important: set instrument pointer to instr 0 (placeholder instrument)
3092 		ch->status = IS_Vol;
3093 		ch->realVol = 0;
3094 		ch->outVol = 0;
3095 		ch->oldVol = 0;
3096 		ch->fFinalVol = 0.0f;
3097 		ch->oldPan = 128;
3098 		ch->outPan = 128;
3099 		ch->finalPan = 128;
3100 		ch->vibDepth = 0;
3101 		ch->midiVibDepth = 0;
3102 		ch->midiPitch = 0;
3103 		ch->portaDirection = 0; // FT2 bugfix: weird 3xx behavior if not used with note
3104 
3105 		stopVoice(i);
3106 	}
3107 
3108 	// for sampling playback line in Smp. Ed.
3109 	editor.curPlayInstr = 255;
3110 	editor.curPlaySmp = 255;
3111 
3112 	stopAllScopes();
3113 	resetAudioDither();
3114 	resetCachedMixerVars();
3115 
3116 	// wait for scope thread to finish, so that we know pointers aren't deprecated
3117 	while (editor.scopeThreadBusy);
3118 
3119 	if (audioWasntLocked)
3120 		unlockAudio();
3121 }
3122 
resetReplayerState(void)3123 void resetReplayerState(void)
3124 {
3125 	song.pattDelTime = song.pattDelTime2 = 0;
3126 	song.posJumpFlag = false;
3127 	song.pBreakPos = 0;
3128 	song.pBreakFlag = false;
3129 
3130 	if (songPlaying)
3131 	{
3132 		song.globalVolume = 64;
3133 
3134 		channel_t *ch = channel;
3135 		for (int32_t i = 0; i < song.numChannels; i++, ch++)
3136 			ch->status |= IS_Vol;
3137 	}
3138 }
3139 
setNewSongPos(int32_t pos)3140 void setNewSongPos(int32_t pos)
3141 {
3142 	resetReplayerState(); // FT2 bugfix
3143 	setPos((int16_t)pos, 0, true);
3144 
3145 	// non-FT2 fix: If song speed was 0, set it back to initial speed
3146 	if (song.speed == 0)
3147 		song.speed = song.initialSpeed;
3148 }
3149 
decSongPos(void)3150 void decSongPos(void)
3151 {
3152 	if (song.songPos == 0)
3153 		return;
3154 
3155 	const bool audioWasntLocked = !audio.locked;
3156 	if (audioWasntLocked)
3157 		lockAudio();
3158 
3159 	if (song.songPos > 0)
3160 		setNewSongPos(song.songPos - 1);
3161 
3162 	if (audioWasntLocked)
3163 		unlockAudio();
3164 }
3165 
incSongPos(void)3166 void incSongPos(void)
3167 {
3168 	if (song.songPos == song.songLength-1)
3169 		return;
3170 
3171 	const bool audioWasntLocked = !audio.locked;
3172 	if (audioWasntLocked)
3173 		lockAudio();
3174 
3175 	if (song.songPos < song.songLength-1)
3176 		setNewSongPos(song.songPos + 1);
3177 
3178 	if (audioWasntLocked)
3179 		unlockAudio();
3180 }
3181 
decCurIns(void)3182 void decCurIns(void)
3183 {
3184 	if (editor.curInstr <= 1)
3185 		return;
3186 
3187 	editor.curInstr--;
3188 	if ((editor.curInstr > 0x40 && !editor.instrBankSwapped) || (editor.curInstr <= 0x40 && editor.instrBankSwapped))
3189 		pbSwapInstrBank();
3190 
3191 	editor.instrBankOffset = ((editor.curInstr - 1) / 8) * 8;
3192 
3193 	updateTextBoxPointers();
3194 	updateNewInstrument();
3195 
3196 	if (ui.advEditShown)
3197 		updateAdvEdit();
3198 }
3199 
incCurIns(void)3200 void incCurIns(void)
3201 {
3202 	if (editor.curInstr >= MAX_INST)
3203 		return;
3204 
3205 	editor.curInstr++;
3206 	if ((editor.curInstr > 0x40 && !editor.instrBankSwapped) || (editor.curInstr <= 0x40 && editor.instrBankSwapped))
3207 		pbSwapInstrBank();
3208 
3209 	editor.instrBankOffset = ((editor.curInstr - 1) / 8) * 8;
3210  	if (editor.instrBankOffset > MAX_INST-8)
3211 		editor.instrBankOffset = MAX_INST-8;
3212 
3213 	updateTextBoxPointers();
3214 	updateNewInstrument();
3215 
3216 	if (ui.advEditShown)
3217 		updateAdvEdit();
3218 }
3219 
decCurSmp(void)3220 void decCurSmp(void)
3221 {
3222 	if (editor.curSmp == 0)
3223 		return;
3224 
3225 	editor.curSmp--;
3226 	editor.sampleBankOffset = (editor.curSmp / 5) * 5;
3227 	setScrollBarPos(SB_SAMPLE_LIST, editor.sampleBankOffset, true);
3228 
3229 	updateTextBoxPointers();
3230 	updateNewSample();
3231 }
3232 
incCurSmp(void)3233 void incCurSmp(void)
3234 {
3235 	if (editor.curSmp >= MAX_SMP_PER_INST-1)
3236 		return;
3237 
3238 	editor.curSmp++;
3239 
3240 	editor.sampleBankOffset = (editor.curSmp / 5) * 5;
3241 	if (editor.sampleBankOffset > MAX_SMP_PER_INST-5)
3242 		editor.sampleBankOffset = MAX_SMP_PER_INST-5;
3243 
3244 	setScrollBarPos(SB_SAMPLE_LIST, editor.sampleBankOffset, true);
3245 
3246 	updateTextBoxPointers();
3247 	updateNewSample();
3248 }
3249 
pbPlaySong(void)3250 void pbPlaySong(void)
3251 {
3252 	startPlaying(PLAYMODE_SONG, 0);
3253 }
3254 
pbPlayPtn(void)3255 void pbPlayPtn(void)
3256 {
3257 	startPlaying(PLAYMODE_PATT, 0);
3258 }
3259 
pbRecSng(void)3260 void pbRecSng(void)
3261 {
3262 	startPlaying(PLAYMODE_RECSONG, 0);
3263 }
3264 
pbRecPtn(void)3265 void pbRecPtn(void)
3266 {
3267 	startPlaying(PLAYMODE_RECPATT, 0);
3268 }
3269 
setSyncedReplayerVars(void)3270 void setSyncedReplayerVars(void)
3271 {
3272 	uint8_t scopeUpdateStatus[MAX_CHANNELS];
3273 
3274 	pattSyncEntry = NULL;
3275 	chSyncEntry = NULL;
3276 
3277 	memset(scopeUpdateStatus, 0, sizeof (scopeUpdateStatus)); // this is needed
3278 
3279 	uint64_t frameTime64 = SDL_GetPerformanceCounter();
3280 
3281 	// handle channel sync queue
3282 
3283 	while (chQueueClearing);
3284 	while (chQueueReadSize() > 0)
3285 	{
3286 		if (frameTime64 < getChQueueTimestamp())
3287 			break; // we have no more stuff to render for now
3288 
3289 		chSyncEntry = chQueuePeek();
3290 		if (chSyncEntry == NULL)
3291 			break;
3292 
3293 		for (int32_t i = 0; i < song.numChannels; i++)
3294 			scopeUpdateStatus[i] |= chSyncEntry->channels[i].status; // yes, OR the status
3295 
3296 		if (!chQueuePop())
3297 			break;
3298 	}
3299 
3300 	/* Extra validation because of possible issues when the buffer is full
3301 	** and positions are being reset, which is not entirely thread safe.
3302 	*/
3303 	if (chSyncEntry != NULL && chSyncEntry->timestamp == 0)
3304 		chSyncEntry = NULL;
3305 
3306 	// handle pattern sync queue
3307 
3308 	while (pattQueueClearing);
3309 	while (pattQueueReadSize() > 0)
3310 	{
3311 		if (frameTime64 < getPattQueueTimestamp())
3312 			break; // we have no more stuff to render for now
3313 
3314 		pattSyncEntry = pattQueuePeek();
3315 		if (pattSyncEntry == NULL)
3316 			break;
3317 
3318 		if (!pattQueuePop())
3319 			break;
3320 	}
3321 
3322 	/* Extra validation because of possible issues when the buffer is full
3323 	** and positions are being reset, which is not entirely thread safe.
3324 	*/
3325 	if (pattSyncEntry != NULL && pattSyncEntry->timestamp == 0)
3326 		pattSyncEntry = NULL;
3327 
3328 	// do actual updates
3329 
3330 	if (chSyncEntry != NULL)
3331 	{
3332 		handleScopesFromChQueue(chSyncEntry, scopeUpdateStatus);
3333 		ui.drawReplayerPianoFlag = true;
3334 	}
3335 
3336 	if (!songPlaying || pattSyncEntry == NULL)
3337 		return;
3338 
3339 	// we have a new tick
3340 
3341 	editor.tick = pattSyncEntry->tick;
3342 
3343 	if (editor.BPM != pattSyncEntry->BPM)
3344 	{
3345 		editor.BPM = pattSyncEntry->BPM;
3346 		ui.drawBPMFlag = true;
3347 	}
3348 
3349 	if (editor.speed != pattSyncEntry->speed)
3350 	{
3351 		editor.speed = pattSyncEntry->speed;
3352 		ui.drawSpeedFlag = true;
3353 	}
3354 
3355 	if (editor.globalVolume != pattSyncEntry->globalVolume)
3356 	{
3357 		editor.globalVolume = pattSyncEntry->globalVolume;
3358 		ui.drawGlobVolFlag = true;
3359 	}
3360 
3361 	if (editor.songPos != pattSyncEntry->songPos)
3362 	{
3363 		editor.songPos = pattSyncEntry->songPos;
3364 		ui.drawPosEdFlag = true;
3365 	}
3366 
3367 	// somewhat of a kludge...
3368 	if (editor.tmpPattern != pattSyncEntry->pattNum || editor.row != pattSyncEntry->row)
3369 	{
3370 		// set pattern number
3371 		editor.editPattern = editor.tmpPattern = pattSyncEntry->pattNum;
3372 		checkMarkLimits();
3373 		ui.drawPattNumLenFlag = true;
3374 
3375 		// set row
3376 		editor.row = (uint8_t)pattSyncEntry->row;
3377 		ui.updatePatternEditor = true;
3378 	}
3379 }
3380