| 
126
 | 
     1 /* - main XM replayer -
 | 
| 
 | 
     2 **
 | 
| 
 | 
     3 ** NOTE: Effect handling is slightly different because
 | 
| 
 | 
     4 ** I've removed the channel muting logic.
 | 
| 
 | 
     5 ** Muted channels would only process *some* effects, but
 | 
| 
 | 
     6 ** since we can't mute channels, we don't care about this.
 | 
| 
 | 
     7 **
 | 
| 
 | 
     8 ** In FT2, the only way to mute a channel is through the
 | 
| 
 | 
     9 ** tracker itself, so this is not really needed in a replayer.
 | 
| 
 | 
    10 */
 | 
| 
 | 
    11 
 | 
| 
 | 
    12 #include <stdio.h>
 | 
| 
 | 
    13 #include <stdint.h>
 | 
| 
 | 
    14 #include <stdbool.h>
 | 
| 
 | 
    15 #include "pmplay.h"
 | 
| 
 | 
    16 #include "pmp_mix.h"
 | 
| 
 | 
    17 #include "snd_masm.h"
 | 
| 
 | 
    18 #include "tables.h"
 | 
| 
 | 
    19 
 | 
| 
 | 
    20 #define MAX_FRQ 32000
 | 
| 
 | 
    21 #define MAX_NOTES (10*12*16+16)
 | 
| 
 | 
    22 
 | 
| 
 | 
    23 static tonTyp nilPatternLine[32]; // 8bb: used for non-allocated (empty) patterns
 | 
| 
 | 
    24 
 | 
| 
 | 
    25 typedef void (*volKolEfxRoutine)(stmTyp *ch);
 | 
| 
 | 
    26 typedef void (*volKolEfxRoutine2)(stmTyp *ch, uint8_t *volKol);
 | 
| 
 | 
    27 typedef void (*efxRoutine)(stmTyp *ch, uint8_t param);
 | 
| 
 | 
    28 
 | 
| 
 | 
    29 static void retrigVolume(stmTyp *ch)
 | 
| 
 | 
    30 {
 | 
| 
 | 
    31 	ch->realVol = ch->oldVol;
 | 
| 
 | 
    32 	ch->outVol = ch->oldVol;
 | 
| 
 | 
    33 	ch->outPan = ch->oldPan;
 | 
| 
 | 
    34 	ch->status |= IS_Vol + IS_Pan + IS_QuickVol;
 | 
| 
 | 
    35 }
 | 
| 
 | 
    36 
 | 
| 
 | 
    37 static void retrigEnvelopeVibrato(stmTyp *ch)
 | 
| 
 | 
    38 {
 | 
| 
 | 
    39 	// 8bb: reset vibrato position
 | 
| 
 | 
    40 	if (!(ch->waveCtrl & 0x04))
 | 
| 
 | 
    41 		ch->vibPos = 0;
 | 
| 
 | 
    42 
 | 
| 
 | 
    43 	/*
 | 
| 
 | 
    44 	** 8bb:
 | 
| 
 | 
    45 	** In FT2.00 .. FT2.09, if the sixth bit of "ch->waveCtrl" is set
 | 
| 
 | 
    46 	** (from effect E7x where x is $4..$7 or $C..$F) and you trigger a note,
 | 
| 
 | 
    47 	** the replayer interrupt will freeze / lock up. This is because of a
 | 
| 
 | 
    48 	** label bug in the original code, causing it to jump back to itself
 | 
| 
 | 
    49 	** indefinitely.
 | 
| 
 | 
    50 	*/
 | 
| 
 | 
    51 
 | 
| 
 | 
    52 	// 8bb: safely reset tremolo position
 | 
| 
 | 
    53 	if (!(ch->waveCtrl & 0x40))
 | 
| 
 | 
    54 		ch->tremPos = 0;
 | 
| 
 | 
    55 
 | 
| 
 | 
    56 	ch->retrigCnt = 0;
 | 
| 
 | 
    57 	ch->tremorPos = 0;
 | 
| 
 | 
    58 
 | 
| 
 | 
    59 	ch->envSustainActive = true;
 | 
| 
 | 
    60 
 | 
| 
 | 
    61 	instrTyp *ins = ch->instrSeg;
 | 
| 
 | 
    62 
 | 
| 
 | 
    63 	if (ins->envVTyp & ENV_ENABLED)
 | 
| 
 | 
    64 	{
 | 
| 
 | 
    65 		ch->envVCnt = 65535;
 | 
| 
 | 
    66 		ch->envVPos = 0;
 | 
| 
 | 
    67 	}
 | 
| 
 | 
    68 
 | 
| 
 | 
    69 	if (ins->envPTyp & ENV_ENABLED)
 | 
| 
 | 
    70 	{
 | 
| 
 | 
    71 		ch->envPCnt = 65535;
 | 
| 
 | 
    72 		ch->envPPos = 0;
 | 
| 
 | 
    73 	}
 | 
| 
 | 
    74 
 | 
| 
 | 
    75 	ch->fadeOutSpeed = ins->fadeOut; // 8bb: ranges 0..4095 (FT2 doesn't check if it's higher than 4095!)
 | 
| 
 | 
    76 
 | 
| 
 | 
    77 	// 8bb: final fadeout range is in fact 0..32768, and not 0..65536 like the XM format doc says
 | 
| 
 | 
    78 	ch->fadeOutAmp = 32768;
 | 
| 
 | 
    79 
 | 
| 
 | 
    80 	if (ins->vibDepth > 0)
 | 
| 
 | 
    81 	{
 | 
| 
 | 
    82 		ch->eVibPos = 0;
 | 
| 
 | 
    83 
 | 
| 
 | 
    84 		if (ins->vibSweep > 0)
 | 
| 
 | 
    85 		{
 | 
| 
 | 
    86 			ch->eVibAmp = 0;
 | 
| 
 | 
    87 			ch->eVibSweep = (ins->vibDepth << 8) / ins->vibSweep;
 | 
| 
 | 
    88 		}
 | 
| 
 | 
    89 		else
 | 
| 
 | 
    90 		{
 | 
| 
 | 
    91 			ch->eVibAmp = ins->vibDepth << 8;
 | 
| 
 | 
    92 			ch->eVibSweep = 0;
 | 
| 
 | 
    93 		}
 | 
| 
 | 
    94 	}
 | 
| 
 | 
    95 }
 | 
| 
 | 
    96 
 | 
| 
 | 
    97 static void keyOff(stmTyp *ch)
 | 
| 
 | 
    98 {
 | 
| 
 | 
    99 	instrTyp *ins = ch->instrSeg;
 | 
| 
 | 
   100 
 | 
| 
 | 
   101 	if (!(ins->envPTyp & ENV_ENABLED)) // 8bb: probably an FT2 bug
 | 
| 
 | 
   102 	{
 | 
| 
 | 
   103 		if (ch->envPCnt >= (uint16_t)ins->envPP[ch->envPPos][0])
 | 
| 
 | 
   104 			ch->envPCnt = ins->envPP[ch->envPPos][0]-1;
 | 
| 
 | 
   105 	}
 | 
| 
 | 
   106 
 | 
| 
 | 
   107 	if (ins->envVTyp & ENV_ENABLED)
 | 
| 
 | 
   108 	{
 | 
| 
 | 
   109 		if (ch->envVCnt >= (uint16_t)ins->envVP[ch->envVPos][0])
 | 
| 
 | 
   110 			ch->envVCnt = ins->envVP[ch->envVPos][0]-1;
 | 
| 
 | 
   111 	}
 | 
| 
 | 
   112 	else
 | 
| 
 | 
   113 	{
 | 
| 
 | 
   114 		ch->realVol = 0;
 | 
| 
 | 
   115 		ch->outVol = 0;
 | 
| 
 | 
   116 		ch->status |= IS_Vol + IS_QuickVol;
 | 
| 
 | 
   117 	}
 | 
| 
 | 
   118 
 | 
| 
 | 
   119 	ch->envSustainActive = false;
 | 
| 
 | 
   120 }
 | 
| 
 | 
   121 
 | 
| 
 | 
   122 uint32_t getFrequenceValue(uint16_t period) // 8bb: converts period to 16.16fp resampling delta
 | 
| 
 | 
   123 {
 | 
| 
 | 
   124 	uint32_t delta;
 | 
| 
 | 
   125 
 | 
| 
 | 
   126 	if (period == 0)
 | 
| 
 | 
   127 		return 0;
 | 
| 
 | 
   128 
 | 
| 
 | 
   129 	if (linearFrqTab)
 | 
| 
 | 
   130 	{
 | 
| 
 | 
   131 		const uint16_t invPeriod = (12 * 192 * 4) - period; // 8bb: this intentionally underflows uint16_t to be accurate to FT2
 | 
| 
 | 
   132 
 | 
| 
 | 
   133 		const uint32_t quotient = invPeriod / 768;
 | 
| 
 | 
   134 		const uint32_t remainder = invPeriod % 768;
 | 
| 
 | 
   135 
 | 
| 
 | 
   136 		const int32_t octShift = 14 - quotient;
 | 
| 
 | 
   137 
 | 
| 
 | 
   138 		delta = (uint32_t)(((int64_t)logTab[remainder] * (int32_t)frequenceMulFactor) >> 24);
 | 
| 
 | 
   139 		delta >>= (octShift & 31); // 8bb: added needed 32-bit bitshift mask
 | 
| 
 | 
   140 	}
 | 
| 
 | 
   141 	else
 | 
| 
 | 
   142 	{
 | 
| 
 | 
   143 		delta = frequenceDivFactor / (uint32_t)period;
 | 
| 
 | 
   144 	}
 | 
| 
 | 
   145 
 | 
| 
 | 
   146 	return delta;
 | 
| 
 | 
   147 }
 | 
| 
 | 
   148 
 | 
| 
 | 
   149 static void startTone(uint8_t ton, uint8_t effTyp, uint8_t eff, stmTyp *ch)
 | 
| 
 | 
   150 {
 | 
| 
 | 
   151 	if (ton == NOTE_KEYOFF)
 | 
| 
 | 
   152 	{
 | 
| 
 | 
   153 		keyOff(ch);
 | 
| 
 | 
   154 		return;
 | 
| 
 | 
   155 	}
 | 
| 
 | 
   156 
 | 
| 
 | 
   157 	// 8bb: if we came from Rxy (retrig), we didn't check note (Ton) yet
 | 
| 
 | 
   158 	if (ton == 0)
 | 
| 
 | 
   159 	{
 | 
| 
 | 
   160 		ton = ch->tonNr;
 | 
| 
 | 
   161 		if (ton == 0)
 | 
| 
 | 
   162 			return; // 8bb: if still no note, return
 | 
| 
 | 
   163 	}
 | 
| 
 | 
   164 
 | 
| 
 | 
   165 	ch->tonNr = ton;
 | 
| 
 | 
   166 
 | 
| 
 | 
   167 	instrTyp *ins = instr[ch->instrNr];
 | 
| 
 | 
   168 	if (ins == NULL)
 | 
| 
 | 
   169 		ins = instr[0];
 | 
| 
 | 
   170 
 | 
| 
 | 
   171 	ch->instrSeg = ins;
 | 
| 
 | 
   172 	ch->mute = ins->mute;
 | 
| 
 | 
   173 
 | 
| 
 | 
   174 	uint8_t smp = ins->ta[ton-1] & 0xF; // 8bb: added for safety
 | 
| 
 | 
   175 	ch->sampleNr = smp;
 | 
| 
 | 
   176 
 | 
| 
 | 
   177 	sampleTyp *s = &ins->samp[smp];
 | 
| 
 | 
   178 	ch->relTonNr = s->relTon;
 | 
| 
 | 
   179 
 | 
| 
 | 
   180 	ton += ch->relTonNr;
 | 
| 
 | 
   181 	if (ton >= 10*12)
 | 
| 
 | 
   182 		return;
 | 
| 
 | 
   183 
 | 
| 
 | 
   184 	ch->oldVol = s->vol;
 | 
| 
 | 
   185 	ch->oldPan = s->pan;
 | 
| 
 | 
   186 
 | 
| 
 | 
   187 	if (effTyp == 0x0E && (eff & 0xF0) == 0x50) // 8bb: EFx - Set Finetune
 | 
| 
 | 
   188 		ch->fineTune = ((eff & 0x0F) << 4) - 128;
 | 
| 
 | 
   189 	else
 | 
| 
 | 
   190 		ch->fineTune = s->fine;
 | 
| 
 | 
   191 
 | 
| 
 | 
   192 	if (ton != 0)
 | 
| 
 | 
   193 	{
 | 
| 
 | 
   194 		const uint16_t tmpTon = ((ton-1) << 4) + (((int8_t)ch->fineTune >> 3) + 16); // 8bb: 0..1935
 | 
| 
 | 
   195 		if (tmpTon < MAX_NOTES) // 8bb: tmpTon is *always* below MAX_NOTES here, this check is not needed
 | 
| 
 | 
   196 			ch->outPeriod = ch->realPeriod = note2Period[tmpTon];
 | 
| 
 | 
   197 	}
 | 
| 
 | 
   198 
 | 
| 
 | 
   199 	ch->status |= IS_Period + IS_Vol + IS_Pan + IS_NyTon + IS_QuickVol;
 | 
| 
 | 
   200 
 | 
| 
 | 
   201 	if (effTyp == 9) // 8bb: 9xx - Set Sample Offset
 | 
| 
 | 
   202 	{
 | 
| 
 | 
   203 		if (eff)
 | 
| 
 | 
   204 			ch->smpOffset = ch->eff;
 | 
| 
 | 
   205 
 | 
| 
 | 
   206 		ch->smpStartPos = ch->smpOffset << 8;
 | 
| 
 | 
   207 	}
 | 
| 
 | 
   208 	else
 | 
| 
 | 
   209 	{
 | 
| 
 | 
   210 		ch->smpStartPos = 0;
 | 
| 
 | 
   211 	}
 | 
| 
 | 
   212 
 | 
| 
 | 
   213 	P_StartTone(s, ch->smpStartPos);
 | 
| 
 | 
   214 }
 | 
| 
 | 
   215 
 | 
| 
 | 
   216 static void volume(stmTyp *ch, uint8_t param); // 8bb: volume slide
 | 
| 
 | 
   217 static void vibrato2(stmTyp *ch);
 | 
| 
 | 
   218 static void tonePorta(stmTyp *ch, uint8_t param);
 | 
| 
 | 
   219 
 | 
| 
 | 
   220 static void dummy(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   221 {
 | 
| 
 | 
   222 	return;
 | 
| 
 | 
   223 
 | 
| 
 | 
   224 	(void)ch;
 | 
| 
 | 
   225 	(void)param;
 | 
| 
 | 
   226 }
 | 
| 
 | 
   227 
 | 
| 
 | 
   228 static void finePortaUp(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   229 {
 | 
| 
 | 
   230 	if (param == 0)
 | 
| 
 | 
   231 		param = ch->fPortaUpSpeed;
 | 
| 
 | 
   232 
 | 
| 
 | 
   233 	ch->fPortaUpSpeed = param;
 | 
| 
 | 
   234 
 | 
| 
 | 
   235 	ch->realPeriod -= param << 2;
 | 
| 
 | 
   236 	if ((int16_t)ch->realPeriod < 1)
 | 
| 
 | 
   237 		ch->realPeriod = 1;
 | 
| 
 | 
   238 
 | 
| 
 | 
   239 	ch->outPeriod = ch->realPeriod;
 | 
| 
 | 
   240 	ch->status |= IS_Period;
 | 
| 
 | 
   241 }
 | 
| 
 | 
   242 
 | 
| 
 | 
   243 static void finePortaDown(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   244 {
 | 
| 
 | 
   245 	if (param == 0)
 | 
| 
 | 
   246 		param = ch->fPortaDownSpeed;
 | 
| 
 | 
   247 
 | 
| 
 | 
   248 	ch->fPortaDownSpeed = param;
 | 
| 
 | 
   249 
 | 
| 
 | 
   250 	ch->realPeriod += param << 2;
 | 
| 
 | 
   251 	if ((int16_t)ch->realPeriod > MAX_FRQ-1) // 8bb: FT2 bug, should've been unsigned comparison!
 | 
| 
 | 
   252 		ch->realPeriod = MAX_FRQ-1;
 | 
| 
 | 
   253 
 | 
| 
 | 
   254 	ch->outPeriod = ch->realPeriod;
 | 
| 
 | 
   255 	ch->status |= IS_Period;
 | 
| 
 | 
   256 }
 | 
| 
 | 
   257 
 | 
| 
 | 
   258 static void setGlissCtrl(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   259 {
 | 
| 
 | 
   260 	ch->glissFunk = param;
 | 
| 
 | 
   261 }
 | 
| 
 | 
   262 
 | 
| 
 | 
   263 static void setVibratoCtrl(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   264 {
 | 
| 
 | 
   265 	ch->waveCtrl = (ch->waveCtrl & 0xF0) | param;
 | 
| 
 | 
   266 }
 | 
| 
 | 
   267 
 | 
| 
 | 
   268 static void jumpLoop(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   269 {
 | 
| 
 | 
   270 	if (param == 0)
 | 
| 
 | 
   271 	{
 | 
| 
 | 
   272 		ch->pattPos = song.pattPos & 0xFF;
 | 
| 
 | 
   273 	}
 | 
| 
 | 
   274 	else if (ch->loopCnt == 0)
 | 
| 
 | 
   275 	{
 | 
| 
 | 
   276 		ch->loopCnt = param;
 | 
| 
 | 
   277 
 | 
| 
 | 
   278 		song.pBreakPos = ch->pattPos;
 | 
| 
 | 
   279 		song.pBreakFlag = true;
 | 
| 
 | 
   280 	}
 | 
| 
 | 
   281 	else if (--ch->loopCnt > 0)
 | 
| 
 | 
   282 	{
 | 
| 
 | 
   283 		song.pBreakPos = ch->pattPos;
 | 
| 
 | 
   284 		song.pBreakFlag = true;
 | 
| 
 | 
   285 	}
 | 
| 
 | 
   286 }
 | 
| 
 | 
   287 
 | 
| 
 | 
   288 static void setTremoloCtrl(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   289 {
 | 
| 
 | 
   290 	ch->waveCtrl = (param << 4) | (ch->waveCtrl & 0x0F);
 | 
| 
 | 
   291 }
 | 
| 
 | 
   292 
 | 
| 
 | 
   293 static void volFineUp(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   294 {
 | 
| 
 | 
   295 	if (param == 0)
 | 
| 
 | 
   296 		param = ch->fVolSlideUpSpeed;
 | 
| 
 | 
   297 
 | 
| 
 | 
   298 	ch->fVolSlideUpSpeed = param;
 | 
| 
 | 
   299 
 | 
| 
 | 
   300 	ch->realVol += param;
 | 
| 
 | 
   301 	if (ch->realVol > 64)
 | 
| 
 | 
   302 		ch->realVol = 64;
 | 
| 
 | 
   303 
 | 
| 
 | 
   304 	ch->outVol = ch->realVol;
 | 
| 
 | 
   305 	ch->status |= IS_Vol;
 | 
| 
 | 
   306 }
 | 
| 
 | 
   307 
 | 
| 
 | 
   308 static void volFineDown(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   309 {
 | 
| 
 | 
   310 	if (param == 0)
 | 
| 
 | 
   311 		param = ch->fVolSlideDownSpeed;
 | 
| 
 | 
   312 
 | 
| 
 | 
   313 	ch->fVolSlideDownSpeed = param;
 | 
| 
 | 
   314 
 | 
| 
 | 
   315 	ch->realVol -= param;
 | 
| 
 | 
   316 	if ((int8_t)ch->realVol < 0)
 | 
| 
 | 
   317 		ch->realVol = 0;
 | 
| 
 | 
   318 
 | 
| 
 | 
   319 	ch->outVol = ch->realVol;
 | 
| 
 | 
   320 	ch->status |= IS_Vol;
 | 
| 
 | 
   321 }
 | 
| 
 | 
   322 
 | 
| 
 | 
   323 static void noteCut0(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   324 {
 | 
| 
 | 
   325 	if (param == 0) // 8bb: only a parameter of zero is handled here
 | 
| 
 | 
   326 	{
 | 
| 
 | 
   327 		ch->realVol = 0;
 | 
| 
 | 
   328 		ch->outVol = 0;
 | 
| 
 | 
   329 		ch->status |= IS_Vol + IS_QuickVol;
 | 
| 
 | 
   330 	}
 | 
| 
 | 
   331 }
 | 
| 
 | 
   332 
 | 
| 
 | 
   333 static void pattDelay(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   334 {
 | 
| 
 | 
   335 	if (song.pattDelTime2 == 0)
 | 
| 
 | 
   336 		song.pattDelTime = param + 1;
 | 
| 
 | 
   337 
 | 
| 
 | 
   338 	(void)ch;
 | 
| 
 | 
   339 }
 | 
| 
 | 
   340 
 | 
| 
 | 
   341 static const efxRoutine EJumpTab_TickZero[16] =
 | 
| 
 | 
   342 {
 | 
| 
 | 
   343 	dummy, // 0
 | 
| 
 | 
   344 	finePortaUp, // 1
 | 
| 
 | 
   345 	finePortaDown, // 2
 | 
| 
 | 
   346 	setGlissCtrl, // 3
 | 
| 
 | 
   347 	setVibratoCtrl, // 4
 | 
| 
 | 
   348 	dummy, // 5
 | 
| 
 | 
   349 	jumpLoop, // 6
 | 
| 
 | 
   350 	setTremoloCtrl, // 7
 | 
| 
 | 
   351 	dummy, // 8
 | 
| 
 | 
   352 	dummy, // 9
 | 
| 
 | 
   353 	volFineUp, // A
 | 
| 
 | 
   354 	volFineDown, // B
 | 
| 
 | 
   355 	noteCut0, // C
 | 
| 
 | 
   356 	dummy, // D
 | 
| 
 | 
   357 	pattDelay, // E
 | 
| 
 | 
   358 	dummy // F
 | 
| 
 | 
   359 };
 | 
| 
 | 
   360 
 | 
| 
 | 
   361 static void E_Effects_TickZero(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   362 {
 | 
| 
 | 
   363 	EJumpTab_TickZero[param >> 4](ch, param & 0x0F);
 | 
| 
 | 
   364 }
 | 
| 
 | 
   365 
 | 
| 
 | 
   366 static void posJump(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   367 {
 | 
| 
 | 
   368 	song.songPos = (int16_t)param - 1;
 | 
| 
 | 
   369 	song.pBreakPos = 0;
 | 
| 
 | 
   370 	song.posJumpFlag = true;
 | 
| 
 | 
   371 
 | 
| 
 | 
   372 	(void)ch;
 | 
| 
 | 
   373 }
 | 
| 
 | 
   374 
 | 
| 
 | 
   375 static void pattBreak(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   376 {
 | 
| 
 | 
   377 	song.posJumpFlag = true;
 | 
| 
 | 
   378 
 | 
| 
 | 
   379 	param = ((param >> 4) * 10) + (param & 0x0F);
 | 
| 
 | 
   380 	if (param <= 63)
 | 
| 
 | 
   381 		song.pBreakPos = param;
 | 
| 
 | 
   382 	else
 | 
| 
 | 
   383 		song.pBreakPos = 0;
 | 
| 
 | 
   384 
 | 
| 
 | 
   385 	(void)ch;
 | 
| 
 | 
   386 }
 | 
| 
 | 
   387 
 | 
| 
 | 
   388 static void setSpeed(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   389 {
 | 
| 
 | 
   390 	if (param >= 32)
 | 
| 
 | 
   391 	{
 | 
| 
 | 
   392 		song.speed = param;
 | 
| 
 | 
   393 		P_SetSpeed(song.speed);
 | 
| 
 | 
   394 	}
 | 
| 
 | 
   395 	else
 | 
| 
 | 
   396 	{
 | 
| 
 | 
   397 		song.timer = song.tempo = param;
 | 
| 
 | 
   398 	}
 | 
| 
 | 
   399 
 | 
| 
 | 
   400 	(void)ch;
 | 
| 
 | 
   401 }
 | 
| 
 | 
   402 
 | 
| 
 | 
   403 static void setGlobaVol(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   404 {
 | 
| 
 | 
   405 	if (param > 64)
 | 
| 
 | 
   406 		param = 64;
 | 
| 
 | 
   407 
 | 
| 
 | 
   408 	song.globVol = param;
 | 
| 
 | 
   409 
 | 
| 
 | 
   410 	stmTyp *c = stm;
 | 
| 
 | 
   411 	for (int32_t i = 0; i < song.antChn; i++, c++) // 8bb: this updates the volume for all voices
 | 
| 
 | 
   412 		c->status |= IS_Vol;
 | 
| 
 | 
   413 
 | 
| 
 | 
   414 	(void)ch;
 | 
| 
 | 
   415 }
 | 
| 
 | 
   416 
 | 
| 
 | 
   417 static void setEnvelopePos(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   418 {
 | 
| 
 | 
   419 	int8_t envPos;
 | 
| 
 | 
   420 	bool envUpdate;
 | 
| 
 | 
   421 	int16_t newEnvPos;
 | 
| 
 | 
   422 
 | 
| 
 | 
   423 	instrTyp *ins = ch->instrSeg;
 | 
| 
 | 
   424 
 | 
| 
 | 
   425 	// *** VOLUME ENVELOPE ***
 | 
| 
 | 
   426 	if (ins->envVTyp & ENV_ENABLED)
 | 
| 
 | 
   427 	{
 | 
| 
 | 
   428 		ch->envVCnt = param - 1;
 | 
| 
 | 
   429 
 | 
| 
 | 
   430 		envPos = 0;
 | 
| 
 | 
   431 		envUpdate = true;
 | 
| 
 | 
   432 		newEnvPos = param;
 | 
| 
 | 
   433 
 | 
| 
 | 
   434 		if (ins->envVPAnt > 1)
 | 
| 
 | 
   435 		{
 | 
| 
 | 
   436 			envPos++;
 | 
| 
 | 
   437 			for (int32_t i = 0; i < ins->envVPAnt-1; i++)
 | 
| 
 | 
   438 			{
 | 
| 
 | 
   439 				if (newEnvPos < ins->envVP[envPos][0])
 | 
| 
 | 
   440 				{
 | 
| 
 | 
   441 					envPos--;
 | 
| 
 | 
   442 
 | 
| 
 | 
   443 					newEnvPos -= ins->envVP[envPos][0];
 | 
| 
 | 
   444 					if (newEnvPos == 0)
 | 
| 
 | 
   445 					{
 | 
| 
 | 
   446 						envUpdate = false;
 | 
| 
 | 
   447 						break;
 | 
| 
 | 
   448 					}
 | 
| 
 | 
   449 
 | 
| 
 | 
   450 					if (ins->envVP[envPos+1][0] <= ins->envVP[envPos][0])
 | 
| 
 | 
   451 					{
 | 
| 
 | 
   452 						envUpdate = true;
 | 
| 
 | 
   453 						break;
 | 
| 
 | 
   454 					}
 | 
| 
 | 
   455 
 | 
| 
 | 
   456 					ch->envVIPValue = ((ins->envVP[envPos+1][1] - ins->envVP[envPos][1]) & 0xFF) << 8;
 | 
| 
 | 
   457 					ch->envVIPValue /= (ins->envVP[envPos+1][0] - ins->envVP[envPos][0]);
 | 
| 
 | 
   458 
 | 
| 
 | 
   459 					ch->envVAmp = (ch->envVIPValue * (newEnvPos - 1)) + ((ins->envVP[envPos][1] & 0xFF) << 8);
 | 
| 
 | 
   460 
 | 
| 
 | 
   461 					envPos++;
 | 
| 
 | 
   462 
 | 
| 
 | 
   463 					envUpdate = false;
 | 
| 
 | 
   464 					break;
 | 
| 
 | 
   465 				}
 | 
| 
 | 
   466 
 | 
| 
 | 
   467 				envPos++;
 | 
| 
 | 
   468 			}
 | 
| 
 | 
   469 
 | 
| 
 | 
   470 			if (envUpdate)
 | 
| 
 | 
   471 				envPos--;
 | 
| 
 | 
   472 		}
 | 
| 
 | 
   473 
 | 
| 
 | 
   474 		if (envUpdate)
 | 
| 
 | 
   475 		{
 | 
| 
 | 
   476 			ch->envVIPValue = 0;
 | 
| 
 | 
   477 			ch->envVAmp = (ins->envVP[envPos][1] & 0xFF) << 8;
 | 
| 
 | 
   478 		}
 | 
| 
 | 
   479 
 | 
| 
 | 
   480 		if (envPos >= ins->envVPAnt)
 | 
| 
 | 
   481 		{
 | 
| 
 | 
   482 			envPos = ins->envVPAnt - 1;
 | 
| 
 | 
   483 			if (envPos < 0)
 | 
| 
 | 
   484 				envPos = 0;
 | 
| 
 | 
   485 		}
 | 
| 
 | 
   486 
 | 
| 
 | 
   487 		ch->envVPos = envPos;
 | 
| 
 | 
   488 	}
 | 
| 
 | 
   489 
 | 
| 
 | 
   490 	// *** PANNING ENVELOPE ***
 | 
| 
 | 
   491 	if (ins->envVTyp & ENV_SUSTAIN) // 8bb: FT2 bug? (should probably have been "ins->envPTyp & ENV_ENABLED")
 | 
| 
 | 
   492 	{
 | 
| 
 | 
   493 		ch->envPCnt = param - 1;
 | 
| 
 | 
   494 
 | 
| 
 | 
   495 		envPos = 0;
 | 
| 
 | 
   496 		envUpdate = true;
 | 
| 
 | 
   497 		newEnvPos = param;
 | 
| 
 | 
   498 
 | 
| 
 | 
   499 		if (ins->envPPAnt > 1)
 | 
| 
 | 
   500 		{
 | 
| 
 | 
   501 			envPos++;
 | 
| 
 | 
   502 			for (int32_t i = 0; i < ins->envPPAnt-1; i++)
 | 
| 
 | 
   503 			{
 | 
| 
 | 
   504 				if (newEnvPos < ins->envPP[envPos][0])
 | 
| 
 | 
   505 				{
 | 
| 
 | 
   506 					envPos--;
 | 
| 
 | 
   507 
 | 
| 
 | 
   508 					newEnvPos -= ins->envPP[envPos][0];
 | 
| 
 | 
   509 					if (newEnvPos == 0)
 | 
| 
 | 
   510 					{
 | 
| 
 | 
   511 						envUpdate = false;
 | 
| 
 | 
   512 						break;
 | 
| 
 | 
   513 					}
 | 
| 
 | 
   514 
 | 
| 
 | 
   515 					if (ins->envPP[envPos + 1][0] <= ins->envPP[envPos][0])
 | 
| 
 | 
   516 					{
 | 
| 
 | 
   517 						envUpdate = true;
 | 
| 
 | 
   518 						break;
 | 
| 
 | 
   519 					}
 | 
| 
 | 
   520 
 | 
| 
 | 
   521 					ch->envPIPValue = ((ins->envPP[envPos+1][1] - ins->envPP[envPos][1]) & 0xFF) << 8;
 | 
| 
 | 
   522 					ch->envPIPValue /= (ins->envPP[envPos+1][0] - ins->envPP[envPos][0]);
 | 
| 
 | 
   523 
 | 
| 
 | 
   524 					ch->envPAmp = (ch->envPIPValue * (newEnvPos - 1)) + ((ins->envPP[envPos][1] & 0xFF) << 8);
 | 
| 
 | 
   525 
 | 
| 
 | 
   526 					envPos++;
 | 
| 
 | 
   527 
 | 
| 
 | 
   528 					envUpdate = false;
 | 
| 
 | 
   529 					break;
 | 
| 
 | 
   530 				}
 | 
| 
 | 
   531 
 | 
| 
 | 
   532 				envPos++;
 | 
| 
 | 
   533 			}
 | 
| 
 | 
   534 
 | 
| 
 | 
   535 			if (envUpdate)
 | 
| 
 | 
   536 				envPos--;
 | 
| 
 | 
   537 		}
 | 
| 
 | 
   538 
 | 
| 
 | 
   539 		if (envUpdate)
 | 
| 
 | 
   540 		{
 | 
| 
 | 
   541 			ch->envPIPValue = 0;
 | 
| 
 | 
   542 			ch->envPAmp = (ins->envPP[envPos][1] & 0xFF) << 8;
 | 
| 
 | 
   543 		}
 | 
| 
 | 
   544 
 | 
| 
 | 
   545 		if (envPos >= ins->envPPAnt)
 | 
| 
 | 
   546 		{
 | 
| 
 | 
   547 			envPos = ins->envPPAnt - 1;
 | 
| 
 | 
   548 			if (envPos < 0)
 | 
| 
 | 
   549 				envPos = 0;
 | 
| 
 | 
   550 		}
 | 
| 
 | 
   551 
 | 
| 
 | 
   552 		ch->envPPos = envPos;
 | 
| 
 | 
   553 	}
 | 
| 
 | 
   554 }
 | 
| 
 | 
   555 
 | 
| 
 | 
   556 /* -- tick-zero volume column effects --
 | 
| 
 | 
   557 ** 2nd parameter is used for a volume column quirk with the Rxy command (multiretrig)
 | 
| 
 | 
   558 */
 | 
| 
 | 
   559 
 | 
| 
 | 
   560 static void v_SetVibSpeed(stmTyp *ch, uint8_t *volKol)
 | 
| 
 | 
   561 {
 | 
| 
 | 
   562 	*volKol = (ch->volKolVol & 0x0F) << 2;
 | 
| 
 | 
   563 	if (*volKol != 0)
 | 
| 
 | 
   564 		ch->vibSpeed = *volKol;
 | 
| 
 | 
   565 }
 | 
| 
 | 
   566 
 | 
| 
 | 
   567 static void v_Volume(stmTyp *ch, uint8_t *volKol)
 | 
| 
 | 
   568 {
 | 
| 
 | 
   569 	*volKol -= 16;
 | 
| 
 | 
   570 	if (*volKol > 64) // 8bb: no idea why FT2 has this check, this can't happen...
 | 
| 
 | 
   571 		*volKol = 64;
 | 
| 
 | 
   572 
 | 
| 
 | 
   573 	ch->outVol = ch->realVol = *volKol;
 | 
| 
 | 
   574 	ch->status |= IS_Vol + IS_QuickVol;
 | 
| 
 | 
   575 }
 | 
| 
 | 
   576 
 | 
| 
 | 
   577 static void v_FineSlideDown(stmTyp *ch, uint8_t *volKol)
 | 
| 
 | 
   578 {
 | 
| 
 | 
   579 	*volKol = (uint8_t)(0 - (ch->volKolVol & 0x0F)) + ch->realVol;
 | 
| 
 | 
   580 	if ((int8_t)*volKol < 0)
 | 
| 
 | 
   581 		*volKol = 0;
 | 
| 
 | 
   582 
 | 
| 
 | 
   583 	ch->outVol = ch->realVol = *volKol;
 | 
| 
 | 
   584 	ch->status |= IS_Vol;
 | 
| 
 | 
   585 }
 | 
| 
 | 
   586 
 | 
| 
 | 
   587 static void v_FineSlideUp(stmTyp *ch, uint8_t *volKol)
 | 
| 
 | 
   588 {
 | 
| 
 | 
   589 	*volKol = (ch->volKolVol & 0x0F) + ch->realVol;
 | 
| 
 | 
   590 	if (*volKol > 64)
 | 
| 
 | 
   591 		*volKol = 64;
 | 
| 
 | 
   592 
 | 
| 
 | 
   593 	ch->outVol = ch->realVol = *volKol;
 | 
| 
 | 
   594 	ch->status |= IS_Vol;
 | 
| 
 | 
   595 }
 | 
| 
 | 
   596 
 | 
| 
 | 
   597 static void v_SetPan(stmTyp *ch, uint8_t *volKol)
 | 
| 
 | 
   598 {
 | 
| 
 | 
   599 	*volKol <<= 4;
 | 
| 
 | 
   600 
 | 
| 
 | 
   601 	ch->outPan = *volKol;
 | 
| 
 | 
   602 	ch->status |= IS_Pan;
 | 
| 
 | 
   603 }
 | 
| 
 | 
   604 
 | 
| 
 | 
   605 // -- non-tick-zero volume column effects --
 | 
| 
 | 
   606 
 | 
| 
 | 
   607 static void v_SlideDown(stmTyp *ch)
 | 
| 
 | 
   608 {
 | 
| 
 | 
   609 	uint8_t newVol = (uint8_t)(0 - (ch->volKolVol & 0x0F)) + ch->realVol;
 | 
| 
 | 
   610 	if ((int8_t)newVol < 0)
 | 
| 
 | 
   611 		newVol = 0;
 | 
| 
 | 
   612 
 | 
| 
 | 
   613 	ch->outVol = ch->realVol = newVol;
 | 
| 
 | 
   614 	ch->status |= IS_Vol;
 | 
| 
 | 
   615 }
 | 
| 
 | 
   616 
 | 
| 
 | 
   617 static void v_SlideUp(stmTyp *ch)
 | 
| 
 | 
   618 {
 | 
| 
 | 
   619 	uint8_t newVol = (ch->volKolVol & 0x0F) + ch->realVol;
 | 
| 
 | 
   620 	if (newVol > 64)
 | 
| 
 | 
   621 		newVol = 64;
 | 
| 
 | 
   622 
 | 
| 
 | 
   623 	ch->outVol = ch->realVol = newVol;
 | 
| 
 | 
   624 	ch->status |= IS_Vol;
 | 
| 
 | 
   625 }
 | 
| 
 | 
   626 
 | 
| 
 | 
   627 static void v_Vibrato(stmTyp *ch)
 | 
| 
 | 
   628 {
 | 
| 
 | 
   629 	const uint8_t param = ch->volKolVol & 0xF;
 | 
| 
 | 
   630 	if (param > 0)
 | 
| 
 | 
   631 		ch->vibDepth = param;
 | 
| 
 | 
   632 
 | 
| 
 | 
   633 	vibrato2(ch);
 | 
| 
 | 
   634 }
 | 
| 
 | 
   635 
 | 
| 
 | 
   636 static void v_PanSlideLeft(stmTyp *ch)
 | 
| 
 | 
   637 {
 | 
| 
 | 
   638 	uint16_t tmp16 = (uint8_t)(0 - (ch->volKolVol & 0x0F)) + ch->outPan;
 | 
| 
 | 
   639 	if (tmp16 < 256) // 8bb: includes an FT2 bug: pan-slide-left of 0 = set pan to 0
 | 
| 
 | 
   640 		tmp16 = 0;
 | 
| 
 | 
   641 
 | 
| 
 | 
   642 	ch->outPan = (uint8_t)tmp16;
 | 
| 
 | 
   643 	ch->status |= IS_Pan;
 | 
| 
 | 
   644 }
 | 
| 
 | 
   645 
 | 
| 
 | 
   646 static void v_PanSlideRight(stmTyp *ch)
 | 
| 
 | 
   647 {
 | 
| 
 | 
   648 	uint16_t tmp16 = (ch->volKolVol & 0x0F) + ch->outPan;
 | 
| 
 | 
   649 	if (tmp16 > 255)
 | 
| 
 | 
   650 		tmp16 = 255;
 | 
| 
 | 
   651 
 | 
| 
 | 
   652 	ch->outPan = (uint8_t)tmp16;
 | 
| 
 | 
   653 	ch->status |= IS_Pan;
 | 
| 
 | 
   654 }
 | 
| 
 | 
   655 
 | 
| 
 | 
   656 static void v_TonePorta(stmTyp *ch)
 | 
| 
 | 
   657 {
 | 
| 
 | 
   658 	tonePorta(ch, 0); // 8bb: the last parameter is actually not used in tonePorta()
 | 
| 
 | 
   659 }
 | 
| 
 | 
   660 
 | 
| 
 | 
   661 static void v_dummy(stmTyp *ch)
 | 
| 
 | 
   662 {
 | 
| 
 | 
   663 	(void)ch;
 | 
| 
 | 
   664 	return;
 | 
| 
 | 
   665 }
 | 
| 
 | 
   666 
 | 
| 
 | 
   667 static void v_dummy2(stmTyp *ch, uint8_t *volKol)
 | 
| 
 | 
   668 {
 | 
| 
 | 
   669 	(void)ch;
 | 
| 
 | 
   670 	(void)volKol;
 | 
| 
 | 
   671 	return;
 | 
| 
 | 
   672 }
 | 
| 
 | 
   673 
 | 
| 
 | 
   674 static const volKolEfxRoutine VJumpTab_TickNonZero[16] =
 | 
| 
 | 
   675 {
 | 
| 
 | 
   676 	v_dummy,        v_dummy,         v_dummy,  v_dummy,
 | 
| 
 | 
   677 	v_dummy,        v_dummy,     v_SlideDown, v_SlideUp,
 | 
| 
 | 
   678 	v_dummy,        v_dummy,         v_dummy, v_Vibrato,
 | 
| 
 | 
   679 	v_dummy, v_PanSlideLeft, v_PanSlideRight, v_TonePorta
 | 
| 
 | 
   680 };
 | 
| 
 | 
   681 
 | 
| 
 | 
   682 static const volKolEfxRoutine2 VJumpTab_TickZero[16] =
 | 
| 
 | 
   683 {
 | 
| 
 | 
   684 	       v_dummy2,      v_Volume,      v_Volume, v_Volume,
 | 
| 
 | 
   685 	       v_Volume,      v_Volume,      v_dummy2, v_dummy2,
 | 
| 
 | 
   686 	v_FineSlideDown, v_FineSlideUp, v_SetVibSpeed, v_dummy2,
 | 
| 
 | 
   687 	       v_SetPan,      v_dummy2,      v_dummy2, v_dummy2
 | 
| 
 | 
   688 };
 | 
| 
 | 
   689 
 | 
| 
 | 
   690 static void setPan(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   691 {
 | 
| 
 | 
   692 	ch->outPan = param;
 | 
| 
 | 
   693 	ch->status |= IS_Pan;
 | 
| 
 | 
   694 }
 | 
| 
 | 
   695 
 | 
| 
 | 
   696 static void setVol(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   697 {
 | 
| 
 | 
   698 	if (param > 64)
 | 
| 
 | 
   699 		param = 64;
 | 
| 
 | 
   700 
 | 
| 
 | 
   701 	ch->outVol = ch->realVol = param;
 | 
| 
 | 
   702 	ch->status |= IS_Vol + IS_QuickVol;
 | 
| 
 | 
   703 }
 | 
| 
 | 
   704 
 | 
| 
 | 
   705 static void xFinePorta(stmTyp *ch, uint8_t param)
 | 
| 
 | 
   706 {
 | 
| 
 | 
   707 	const uint8_t type = param >> 4;
 | 
| 
 | 
   708 	param &= 0x0F;
 | 
| 
 | 
   709 
 | 
| 
 | 
   710 	if (type == 0x1) // extra fine porta up
 | 
| 
 | 
   711 	{
 | 
| 
 | 
   712 		if (param == 0)
 | 
| 
 | 
   713 			param = ch->ePortaUpSpeed;
 | 
| 
 | 
   714 
 | 
| 
 | 
   715 		ch->ePortaUpSpeed = param;
 | 
| 
 | 
   716 
 | 
| 
 | 
   717 		uint16_t newPeriod = ch->realPeriod;
 | 
| 
 | 
   718 
 | 
| 
 | 
   719 		newPeriod -= param;
 | 
| 
 | 
   720 		if ((int16_t)newPeriod < 1)
 | 
| 
 | 
   721 			newPeriod = 1;
 | 
| 
 | 
   722 
 | 
| 
 | 
   723 		ch->outPeriod = ch->realPeriod = newPeriod;
 | 
| 
 | 
   724 		ch->status |= IS_Period;
 | 
| 
 | 
   725 	}
 | 
| 
 | 
   726 	else if (type == 0x2) // extra fine porta down
 | 
| 
 | 
   727 	{
 | 
| 
 | 
   728 		if (param == 0)
 | 
| 
 | 
   729 			param = ch->ePortaDownSpeed;
 | 
| 
 | 
   730 
 | 
| 
 | 
   731 		ch->ePortaDownSpeed = param;
 | 
| 
 | 
   732 
 | 
| 
 | 
   733 		uint16_t newPeriod = ch->realPeriod;
 | 
| 
 | 
   734 
 | 
| 
 | 
   735 		newPeriod += param;
 | 
| 
 | 
   736 		if ((int16_t)newPeriod > MAX_FRQ-1) // 8bb: FT2 bug, should've been unsigned comparison!
 | 
| 
 | 
   737 			newPeriod = MAX_FRQ-1;
 | 
| 
 | 
   738 
 | 
| 
 | 
   739 		ch->outPeriod = ch->realPeriod = newPeriod;
 | 
| 
 | 
   740 		ch->status |= IS_Period;
 | 
| 
 | 
   741 	}
 | 
| 
 | 
   742 }
 | 
| 
 | 
   743 
 | 
| 
 | 
   744 static void doMultiRetrig(stmTyp *ch, uint8_t param) // 8bb: "param" is never used (needed for efx jumptable structure)
 | 
| 
 | 
   745 {
 | 
| 
 | 
   746 	uint8_t cnt = ch->retrigCnt + 1;
 | 
| 
 | 
   747 	if (cnt < ch->retrigSpeed)
 | 
| 
 | 
   748 	{
 | 
| 
 | 
   749 		ch->retrigCnt = cnt;
 | 
| 
 | 
   750 		return;
 | 
| 
 | 
   751 	}
 | 
| 
 | 
   752 
 | 
| 
 | 
   753 	ch->retrigCnt = 0;
 | 
| 
 | 
   754 
 | 
| 
 | 
   755 	int16_t vol = ch->realVol;
 | 
| 
 | 
   756 	switch (ch->retrigVol)
 | 
| 
 | 
   757 	{
 | 
| 
 | 
   758 		case 0x1: vol -= 1; break;
 | 
| 
 | 
   759 		case 0x2: vol -= 2; break;
 | 
| 
 | 
   760 		case 0x3: vol -= 4; break;
 | 
| 
 | 
   761 		case 0x4: vol -= 8; break;
 | 
| 
 | 
   762 		case 0x5: vol -= 16; break;
 | 
| 
 | 
   763 		case 0x6: vol = (vol >> 1) + (vol >> 3) + (vol >> 4); break;
 | 
| 
 | 
   764 		case 0x7: vol >>= 1; break;
 | 
| 
 | 
   765 		case 0x8: break; // 8bb: does not change the volume
 | 
| 
 | 
   766 		case 0x9: vol += 1; break;
 | 
| 
 | 
   767 		case 0xA: vol += 2; break;
 | 
| 
 | 
   768 		case 0xB: vol += 4; break;
 | 
| 
 | 
   769 		case 0xC: vol += 8; break;
 | 
| 
 | 
   770 		case 0xD: vol += 16; break;
 | 
| 
 | 
   771 		case 0xE: vol = (vol >> 1) + vol; break;
 | 
| 
 | 
   772 		case 0xF: vol += vol; break;
 | 
| 
 | 
   773 		default: break;
 | 
| 
 | 
   774 	}
 | 
| 
 | 
   775 	vol = CLAMP(vol, 0, 64);
 | 
| 
 | 
   776 
 | 
| 
 | 
   777 	ch->realVol = (uint8_t)vol;
 | 
| 
 | 
   778 	ch->outVol = ch->realVol;
 | 
| 
 | 
   779 
 | 
| 
 | 
   780 	if (ch->volKolVol >= 0x10 && ch->volKolVol <= 0x50) // 8bb: Set Volume (volume column)
 | 
| 
 | 
   781 	{
 | 
| 
 | 
   782 		ch->outVol = ch->volKolVol - 0x10;
 | 
| 
 | 
   783 		ch->realVol = ch->outVol;
 | 
| 
 | 
   784 	}
 | 
| 
 | 
   785 	else if (ch->volKolVol >= 0xC0 && ch->volKolVol <= 0xCF) // 8bb: Set Panning (volume column)
 | 
| 
 | 
   786 	{
 | 
| 
 | 
   787 		ch->outPan = (ch->volKolVol & 0x0F) << 4;
 | 
| 
 | 
   788 	}
 | 
| 
 | 
   789 
 | 
| 
 | 
   790 	startTone(0, 0, 0, ch);
 | 
| 
 | 
   791 
 | 
| 
 | 
   792 	(void)param;
 | 
| 
 | 
   793 }
 | 
| 
 | 
   794 
 | 
| 
 | 
   795 static void multiRetrig(stmTyp *ch, uint8_t param, uint8_t volumeColumnData)
 | 
| 
 | 
   796 {
 | 
| 
 | 
   797 	uint8_t tmpParam;
 | 
| 
 | 
   798 
 | 
| 
 | 
   799 	tmpParam = param & 0x0F;
 | 
| 
 | 
   800 	if (tmpParam == 0)
 | 
| 
 | 
   801 		tmpParam = ch->retrigSpeed;
 | 
| 
 | 
   802 
 | 
| 
 | 
   803 	ch->retrigSpeed = tmpParam;
 | 
| 
 | 
   804 
 | 
| 
 | 
   805 	tmpParam = param >> 4;
 | 
| 
 | 
   806 	if (tmpParam == 0)
 | 
| 
 | 
   807 		tmpParam = ch->retrigVol;
 | 
| 
 | 
   808 
 | 
| 
 | 
   809 	ch->retrigVol = tmpParam;
 | 
| 
 | 
   810 
 | 
| 
 | 
   811 	if (volumeColumnData == 0)
 | 
| 
 | 
   812 		doMultiRetrig(ch, 0); // 8bb: the second parameter is never used (needed for efx jumptable structure)
 | 
| 
 | 
   813 }
 | 
| 
 | 
   814 
 | 
| 
 | 
   815 static const efxRoutine JumpTab_TickZero[36] =
 | 
| 
 | 
   816 {
 | 
| 
 | 
   817 	dummy, // 0
 | 
| 
 | 
   818 	dummy, // 1
 | 
| 
 | 
   819 	dummy, // 2
 | 
| 
 | 
   820 	dummy, // 3
 | 
| 
 | 
   821 	dummy, // 4
 | 
| 
 | 
   822 	dummy, // 5
 | 
| 
 | 
   823 	dummy, // 6
 | 
| 
 | 
   824 	dummy, // 7
 | 
| 
 | 
   825 	setPan, // 8
 | 
| 
 | 
   826 	dummy, // 9
 | 
| 
 | 
   827 	dummy, // A
 | 
| 
 | 
   828 	posJump, // B
 | 
| 
 | 
   829 	setVol, // C
 | 
| 
 | 
   830 	pattBreak, // D
 | 
| 
 | 
   831 	E_Effects_TickZero, // E
 | 
| 
 | 
   832 	setSpeed, // F
 | 
| 
 | 
   833 	setGlobaVol, // G
 | 
| 
 | 
   834 	dummy, // H
 | 
| 
 | 
   835 	dummy, // I
 | 
| 
 | 
   836 	dummy, // J
 | 
| 
 | 
   837 	dummy, // K
 | 
| 
 | 
   838 	setEnvelopePos, // L
 | 
| 
 | 
   839 	dummy, // M
 | 
| 
 | 
   840 	dummy, // N
 | 
| 
 | 
   841 	dummy, // O
 | 
| 
 | 
   842 	dummy, // P
 | 
| 
 | 
   843 	dummy, // Q
 | 
| 
 | 
   844 	dummy, // R
 | 
| 
 | 
   845 	dummy, // S
 | 
| 
 | 
   846 	dummy, // T
 | 
| 
 | 
   847 	dummy, // U
 | 
| 
 | 
   848 	dummy, // V
 | 
| 
 | 
   849 	dummy, // W
 | 
| 
 | 
   850 	xFinePorta, // X
 | 
| 
 | 
   851 	dummy, // Y
 | 
| 
 | 
   852 	dummy  // Z
 | 
| 
 | 
   853 };
 | 
| 
 | 
   854 
 | 
| 
 | 
   855 static void checkEffects(stmTyp *ch) // tick0 effect handling
 | 
| 
 | 
   856 {
 | 
| 
 | 
   857 	// volume column effects
 | 
| 
 | 
   858 	uint8_t newVolKol = ch->volKolVol; // 8bb: manipulated by vol. column effects, then used for multiretrig check (FT2 quirk)
 | 
| 
 | 
   859 	VJumpTab_TickZero[ch->volKolVol >> 4](ch, &newVolKol);
 | 
| 
 | 
   860 
 | 
| 
 | 
   861 	// normal effects
 | 
| 
 | 
   862 	const uint8_t param = ch->eff;
 | 
| 
 | 
   863 
 | 
| 
 | 
   864 	if ((ch->effTyp == 0 && param == 0) || ch->effTyp > 35)
 | 
| 
 | 
   865 		return;
 | 
| 
 | 
   866 
 | 
| 
 | 
   867 	// 8bb: this one has to be done here instead of in the jumptable, as it needs the "newVolKol" parameter (FT2 quirk)
 | 
| 
 | 
   868 	if (ch->effTyp == 27) // 8bb: Rxy - Multi Retrig
 | 
| 
 | 
   869 	{
 | 
| 
 | 
   870 		multiRetrig(ch, param, newVolKol);
 | 
| 
 | 
   871 		return;
 | 
| 
 | 
   872 	}
 | 
| 
 | 
   873 
 | 
| 
 | 
   874 	JumpTab_TickZero[ch->effTyp](ch, ch->eff);
 | 
| 
 | 
   875 }
 | 
| 
 | 
   876 
 | 
| 
 | 
   877 static void fixTonePorta(stmTyp *ch, const tonTyp *p, uint8_t inst)
 | 
| 
 | 
   878 {
 | 
| 
 | 
   879 	if (p->ton > 0)
 | 
| 
 | 
   880 	{
 | 
| 
 | 
   881 		if (p->ton == NOTE_KEYOFF)
 | 
| 
 | 
   882 		{
 | 
| 
 | 
   883 			keyOff(ch);
 | 
| 
 | 
   884 		}
 | 
| 
 | 
   885 		else
 | 
| 
 | 
   886 		{
 | 
| 
 | 
   887 			const uint16_t portaTmp = (((p->ton-1) + ch->relTonNr) << 4) + (((int8_t)ch->fineTune >> 3) + 16);
 | 
| 
 | 
   888 			if (portaTmp < MAX_NOTES)
 | 
| 
 | 
   889 			{
 | 
| 
 | 
   890 				ch->wantPeriod = note2Period[portaTmp];
 | 
| 
 | 
   891 
 | 
| 
 | 
   892 				if (ch->wantPeriod == ch->realPeriod)
 | 
| 
 | 
   893 					ch->portaDir = 0;
 | 
| 
 | 
   894 				else if (ch->wantPeriod > ch->realPeriod)
 | 
| 
 | 
   895 					ch->portaDir = 1;
 | 
| 
 | 
   896 				else
 | 
| 
 | 
   897 					ch->portaDir = 2;
 | 
| 
 | 
   898 			}
 | 
| 
 | 
   899 		}
 | 
| 
 | 
   900 	}
 | 
| 
 | 
   901 
 | 
| 
 | 
   902 	if (inst > 0)
 | 
| 
 | 
   903 	{
 | 
| 
 | 
   904 		retrigVolume(ch);
 | 
| 
 | 
   905 
 | 
| 
 | 
   906 		if (p->ton != NOTE_KEYOFF)
 | 
| 
 | 
   907 			retrigEnvelopeVibrato(ch);
 | 
| 
 | 
   908 	}
 | 
| 
 | 
   909 }
 | 
| 
 | 
   910 
 | 
| 
 | 
   911 static void getNewNote(stmTyp *ch, const tonTyp *p)
 | 
| 
 | 
   912 {
 | 
| 
 | 
   913 	ch->volKolVol = p->vol;
 | 
| 
 | 
   914 
 | 
| 
 | 
   915 	if (ch->effTyp == 0)
 | 
| 
 | 
   916 	{
 | 
| 
 | 
   917 		if (ch->eff != 0) // 8bb: we have an arpeggio (0xy) running, set period back
 | 
| 
 | 
   918 		{
 | 
| 
 | 
   919 			ch->outPeriod = ch->realPeriod;
 | 
| 
 | 
   920 			ch->status |= IS_Period;
 | 
| 
 | 
   921 		}
 | 
| 
 | 
   922 	}
 | 
| 
 | 
   923 	else
 | 
| 
 | 
   924 	{
 | 
| 
 | 
   925 		// 8bb: if we have a vibrato (4xy/6xy) on previous row (ch) that ends at current row (p), set period back
 | 
| 
 | 
   926 		if ((ch->effTyp == 4 || ch->effTyp == 6) && (p->effTyp != 4 && p->effTyp != 6))
 | 
| 
 | 
   927 		{
 | 
| 
 | 
   928 			ch->outPeriod = ch->realPeriod;
 | 
| 
 | 
   929 			ch->status |= IS_Period;
 | 
| 
 | 
   930 		}
 | 
| 
 | 
   931 	}
 | 
| 
 | 
   932 
 | 
| 
 | 
   933 	ch->effTyp = p->effTyp;
 | 
| 
 | 
   934 	ch->eff = p->eff;
 | 
| 
 | 
   935 	ch->tonTyp = (p->instr << 8) | p->ton;
 | 
| 
 | 
   936 
 | 
| 
 | 
   937 	// 8bb: 'inst' var is used for later if-checks
 | 
| 
 | 
   938 	uint8_t inst = p->instr;
 | 
| 
 | 
   939 	if (inst > 0)
 | 
| 
 | 
   940 	{
 | 
| 
 | 
   941 		if (inst <= 128)
 | 
| 
 | 
   942 			ch->instrNr = inst;
 | 
| 
 | 
   943 		else
 | 
| 
 | 
   944 			inst = 0;
 | 
| 
 | 
   945 	}
 | 
| 
 | 
   946 
 | 
| 
 | 
   947 	bool checkEfx = true;
 | 
| 
 | 
   948 	if (p->effTyp == 0x0E) // 8bb: check for EDx (Note Delay) and E90 (Retrigger Note)
 | 
| 
 | 
   949 	{
 | 
| 
 | 
   950 		if (p->eff >= 0xD1 && p->eff <= 0xDF) // 8bb: ED1..EDF (Note Delay)
 | 
| 
 | 
   951 			return;
 | 
| 
 | 
   952 		else if (p->eff == 0x90) // 8bb: E90 (Retrigger Note)
 | 
| 
 | 
   953 			checkEfx = false;
 | 
| 
 | 
   954 	}
 | 
| 
 | 
   955 
 | 
| 
 | 
   956 	if (checkEfx)
 | 
| 
 | 
   957 	{
 | 
| 
 | 
   958 		if ((ch->volKolVol & 0xF0) == 0xF0) // 8bb: Portamento (volume column)
 | 
| 
 | 
   959 		{
 | 
| 
 | 
   960 			const uint8_t volKolParam = ch->volKolVol & 0x0F;
 | 
| 
 | 
   961 			if (volKolParam > 0)
 | 
| 
 | 
   962 				ch->portaSpeed = volKolParam << 6;
 | 
| 
 | 
   963 
 | 
| 
 | 
   964 			fixTonePorta(ch, p, inst);
 | 
| 
 | 
   965 			checkEffects(ch);
 | 
| 
 | 
   966 			return;
 | 
| 
 | 
   967 		}
 | 
| 
 | 
   968 
 | 
| 
 | 
   969 		if (p->effTyp == 3 || p->effTyp == 5) // 8bb: Portamento (3xx/5xx)
 | 
| 
 | 
   970 		{
 | 
| 
 | 
   971 			if (p->effTyp != 5 && p->eff != 0)
 | 
| 
 | 
   972 				ch->portaSpeed = p->eff << 2;
 | 
| 
 | 
   973 
 | 
| 
 | 
   974 			fixTonePorta(ch, p, inst);
 | 
| 
 | 
   975 			checkEffects(ch);
 | 
| 
 | 
   976 			return;
 | 
| 
 | 
   977 		}
 | 
| 
 | 
   978 
 | 
| 
 | 
   979 		if (p->effTyp == 0x14 && p->eff == 0) // 8bb: K00 (Key Off - only handle tick 0 here)
 | 
| 
 | 
   980 		{
 | 
| 
 | 
   981 			keyOff(ch);
 | 
| 
 | 
   982 
 | 
| 
 | 
   983 			if (inst)
 | 
| 
 | 
   984 				retrigVolume(ch);
 | 
| 
 | 
   985 
 | 
| 
 | 
   986 			checkEffects(ch);
 | 
| 
 | 
   987 			return;
 | 
| 
 | 
   988 		}
 | 
| 
 | 
   989 
 | 
| 
 | 
   990 		if (p->ton == 0)
 | 
| 
 | 
   991 		{
 | 
| 
 | 
   992 			if (inst > 0)
 | 
| 
 | 
   993 			{
 | 
| 
 | 
   994 				retrigVolume(ch);
 | 
| 
 | 
   995 				retrigEnvelopeVibrato(ch);
 | 
| 
 | 
   996 			}
 | 
| 
 | 
   997 
 | 
| 
 | 
   998 			checkEffects(ch);
 | 
| 
 | 
   999 			return;
 | 
| 
 | 
  1000 		}
 | 
| 
 | 
  1001 	}
 | 
| 
 | 
  1002 
 | 
| 
 | 
  1003 	if (p->ton == NOTE_KEYOFF)
 | 
| 
 | 
  1004 		keyOff(ch);
 | 
| 
 | 
  1005 	else
 | 
| 
 | 
  1006 		startTone(p->ton, p->effTyp, p->eff, ch);
 | 
| 
 | 
  1007 
 | 
| 
 | 
  1008 	if (inst > 0)
 | 
| 
 | 
  1009 	{
 | 
| 
 | 
  1010 		retrigVolume(ch);
 | 
| 
 | 
  1011 		if (p->ton != NOTE_KEYOFF)
 | 
| 
 | 
  1012 			retrigEnvelopeVibrato(ch);
 | 
| 
 | 
  1013 	}
 | 
| 
 | 
  1014 
 | 
| 
 | 
  1015 	checkEffects(ch);
 | 
| 
 | 
  1016 }
 | 
| 
 | 
  1017 
 | 
| 
 | 
  1018 static void fixaEnvelopeVibrato(stmTyp *ch)
 | 
| 
 | 
  1019 {
 | 
| 
 | 
  1020 	bool envInterpolateFlag, envDidInterpolate;
 | 
| 
 | 
  1021 	uint8_t envPos;
 | 
| 
 | 
  1022 	int16_t autoVibVal;
 | 
| 
 | 
  1023 	uint16_t autoVibAmp, envVal;
 | 
| 
 | 
  1024 	uint32_t vol;
 | 
| 
 | 
  1025 
 | 
| 
 | 
  1026 	instrTyp *ins = ch->instrSeg;
 | 
| 
 | 
  1027 
 | 
| 
 | 
  1028 	// *** FADEOUT ***
 | 
| 
 | 
  1029 	if (!ch->envSustainActive)
 | 
| 
 | 
  1030 	{
 | 
| 
 | 
  1031 		ch->status |= IS_Vol;
 | 
| 
 | 
  1032 
 | 
| 
 | 
  1033 		if (ch->fadeOutAmp >= ch->fadeOutSpeed)
 | 
| 
 | 
  1034 		{
 | 
| 
 | 
  1035 			ch->fadeOutAmp -= ch->fadeOutSpeed;
 | 
| 
 | 
  1036 		}
 | 
| 
 | 
  1037 		else
 | 
| 
 | 
  1038 		{
 | 
| 
 | 
  1039 			ch->fadeOutAmp = 0;
 | 
| 
 | 
  1040 			ch->fadeOutSpeed = 0;
 | 
| 
 | 
  1041 		}
 | 
| 
 | 
  1042 	}
 | 
| 
 | 
  1043 
 | 
| 
 | 
  1044 	if (!ch->mute)
 | 
| 
 | 
  1045 	{
 | 
| 
 | 
  1046 		// *** VOLUME ENVELOPE ***
 | 
| 
 | 
  1047 		envVal = 0;
 | 
| 
 | 
  1048 		if (ins->envVTyp & ENV_ENABLED)
 | 
| 
 | 
  1049 		{
 | 
| 
 | 
  1050 			envDidInterpolate = false;
 | 
| 
 | 
  1051 			envPos = ch->envVPos;
 | 
| 
 | 
  1052 
 | 
| 
 | 
  1053 			if (++ch->envVCnt == ins->envVP[envPos][0])
 | 
| 
 | 
  1054 			{
 | 
| 
 | 
  1055 				ch->envVAmp = ins->envVP[envPos][1] << 8;
 | 
| 
 | 
  1056 
 | 
| 
 | 
  1057 				envPos++;
 | 
| 
 | 
  1058 				if (ins->envVTyp & ENV_LOOP)
 | 
| 
 | 
  1059 				{
 | 
| 
 | 
  1060 					envPos--;
 | 
| 
 | 
  1061 
 | 
| 
 | 
  1062 					if (envPos == ins->envVRepE)
 | 
| 
 | 
  1063 					{
 | 
| 
 | 
  1064 						if (!(ins->envVTyp & ENV_SUSTAIN) || envPos != ins->envVSust || ch->envSustainActive)
 | 
| 
 | 
  1065 						{
 | 
| 
 | 
  1066 							envPos = ins->envVRepS;
 | 
| 
 | 
  1067 
 | 
| 
 | 
  1068 							ch->envVCnt = ins->envVP[envPos][0];
 | 
| 
 | 
  1069 							ch->envVAmp = ins->envVP[envPos][1] << 8;
 | 
| 
 | 
  1070 						}
 | 
| 
 | 
  1071 					}
 | 
| 
 | 
  1072 
 | 
| 
 | 
  1073 					envPos++;
 | 
| 
 | 
  1074 				}
 | 
| 
 | 
  1075 
 | 
| 
 | 
  1076 				if (envPos < ins->envVPAnt)
 | 
| 
 | 
  1077 				{
 | 
| 
 | 
  1078 					envInterpolateFlag = true;
 | 
| 
 | 
  1079 					if ((ins->envVTyp & ENV_SUSTAIN) && ch->envSustainActive)
 | 
| 
 | 
  1080 					{
 | 
| 
 | 
  1081 						if (envPos-1 == ins->envVSust)
 | 
| 
 | 
  1082 						{
 | 
| 
 | 
  1083 							envPos--;
 | 
| 
 | 
  1084 							ch->envVIPValue = 0;
 | 
| 
 | 
  1085 							envInterpolateFlag = false;
 | 
| 
 | 
  1086 						}
 | 
| 
 | 
  1087 					}
 | 
| 
 | 
  1088 
 | 
| 
 | 
  1089 					if (envInterpolateFlag)
 | 
| 
 | 
  1090 					{
 | 
| 
 | 
  1091 						ch->envVPos = envPos;
 | 
| 
 | 
  1092 
 | 
| 
 | 
  1093 						ch->envVIPValue = 0;
 | 
| 
 | 
  1094 						if (ins->envVP[envPos][0] > ins->envVP[envPos-1][0])
 | 
| 
 | 
  1095 						{
 | 
| 
 | 
  1096 							ch->envVIPValue = (ins->envVP[envPos][1] - ins->envVP[envPos-1][1]) << 8;
 | 
| 
 | 
  1097 							ch->envVIPValue /= (ins->envVP[envPos][0] - ins->envVP[envPos-1][0]);
 | 
| 
 | 
  1098 
 | 
| 
 | 
  1099 							envVal = ch->envVAmp;
 | 
| 
 | 
  1100 							envDidInterpolate = true;
 | 
| 
 | 
  1101 						}
 | 
| 
 | 
  1102 					}
 | 
| 
 | 
  1103 				}
 | 
| 
 | 
  1104 				else
 | 
| 
 | 
  1105 				{
 | 
| 
 | 
  1106 					ch->envVIPValue = 0;
 | 
| 
 | 
  1107 				}
 | 
| 
 | 
  1108 			}
 | 
| 
 | 
  1109 
 | 
| 
 | 
  1110 			if (!envDidInterpolate)
 | 
| 
 | 
  1111 			{
 | 
| 
 | 
  1112 				ch->envVAmp += ch->envVIPValue;
 | 
| 
 | 
  1113 
 | 
| 
 | 
  1114 				envVal = ch->envVAmp;
 | 
| 
 | 
  1115 				if (envVal > 64*256)
 | 
| 
 | 
  1116 				{
 | 
| 
 | 
  1117 					if (envVal > 128*256)
 | 
| 
 | 
  1118 						envVal = 64*256;
 | 
| 
 | 
  1119 					else
 | 
| 
 | 
  1120 						envVal = 0;
 | 
| 
 | 
  1121 
 | 
| 
 | 
  1122 					ch->envVIPValue = 0;
 | 
| 
 | 
  1123 				}
 | 
| 
 | 
  1124 			}
 | 
| 
 | 
  1125 
 | 
| 
 | 
  1126 			envVal >>= 8;
 | 
| 
 | 
  1127 
 | 
| 
 | 
  1128 			vol = (envVal * ch->outVol * ch->fadeOutAmp) >> (16+2);
 | 
| 
 | 
  1129 			vol = (vol * song.globVol) >> 7;
 | 
| 
 | 
  1130 
 | 
| 
 | 
  1131 			ch->status |= IS_Vol; // 8bb: this updates vol on every tick (because vol envelope is enabled)
 | 
| 
 | 
  1132 		}
 | 
| 
 | 
  1133 		else
 | 
| 
 | 
  1134 		{
 | 
| 
 | 
  1135 			vol = ((ch->outVol << 4) * ch->fadeOutAmp) >> 16;
 | 
| 
 | 
  1136 			vol = (vol * song.globVol) >> 7;
 | 
| 
 | 
  1137 		}
 | 
| 
 | 
  1138 
 | 
| 
 | 
  1139 		ch->finalVol = (uint16_t)vol; // 0..256
 | 
| 
 | 
  1140 	}
 | 
| 
 | 
  1141 	else
 | 
| 
 | 
  1142 	{
 | 
| 
 | 
  1143 		ch->finalVol = 0;
 | 
| 
 | 
  1144 	}
 | 
| 
 | 
  1145 
 | 
| 
 | 
  1146 	// *** PANNING ENVELOPE ***
 | 
| 
 | 
  1147 
 | 
| 
 | 
  1148 	envVal = 0;
 | 
| 
 | 
  1149 	if (ins->envPTyp & ENV_ENABLED)
 | 
| 
 | 
  1150 	{
 | 
| 
 | 
  1151 		envDidInterpolate = false;
 | 
| 
 | 
  1152 		envPos = ch->envPPos;
 | 
| 
 | 
  1153 
 | 
| 
 | 
  1154 		if (++ch->envPCnt == ins->envPP[envPos][0])
 | 
| 
 | 
  1155 		{
 | 
| 
 | 
  1156 			ch->envPAmp = ins->envPP[envPos][1] << 8;
 | 
| 
 | 
  1157 
 | 
| 
 | 
  1158 			envPos++;
 | 
| 
 | 
  1159 			if (ins->envPTyp & ENV_LOOP)
 | 
| 
 | 
  1160 			{
 | 
| 
 | 
  1161 				envPos--;
 | 
| 
 | 
  1162 
 | 
| 
 | 
  1163 				if (envPos == ins->envPRepE)
 | 
| 
 | 
  1164 				{
 | 
| 
 | 
  1165 					if (!(ins->envPTyp & ENV_SUSTAIN) || envPos != ins->envPSust || ch->envSustainActive)
 | 
| 
 | 
  1166 					{
 | 
| 
 | 
  1167 						envPos = ins->envPRepS;
 | 
| 
 | 
  1168 
 | 
| 
 | 
  1169 						ch->envPCnt = ins->envPP[envPos][0];
 | 
| 
 | 
  1170 						ch->envPAmp = ins->envPP[envPos][1] << 8;
 | 
| 
 | 
  1171 					}
 | 
| 
 | 
  1172 				}
 | 
| 
 | 
  1173 
 | 
| 
 | 
  1174 				envPos++;
 | 
| 
 | 
  1175 			}
 | 
| 
 | 
  1176 
 | 
| 
 | 
  1177 			if (envPos < ins->envPPAnt)
 | 
| 
 | 
  1178 			{
 | 
| 
 | 
  1179 				envInterpolateFlag = true;
 | 
| 
 | 
  1180 				if ((ins->envPTyp & ENV_SUSTAIN) && ch->envSustainActive)
 | 
| 
 | 
  1181 				{
 | 
| 
 | 
  1182 					if (envPos-1 == ins->envPSust)
 | 
| 
 | 
  1183 					{
 | 
| 
 | 
  1184 						envPos--;
 | 
| 
 | 
  1185 						ch->envPIPValue = 0;
 | 
| 
 | 
  1186 						envInterpolateFlag = false;
 | 
| 
 | 
  1187 					}
 | 
| 
 | 
  1188 				}
 | 
| 
 | 
  1189 
 | 
| 
 | 
  1190 				if (envInterpolateFlag)
 | 
| 
 | 
  1191 				{
 | 
| 
 | 
  1192 					ch->envPPos = envPos;
 | 
| 
 | 
  1193 
 | 
| 
 | 
  1194 					ch->envPIPValue = 0;
 | 
| 
 | 
  1195 					if (ins->envPP[envPos][0] > ins->envPP[envPos-1][0])
 | 
| 
 | 
  1196 					{
 | 
| 
 | 
  1197 						ch->envPIPValue = (ins->envPP[envPos][1] - ins->envPP[envPos-1][1]) << 8;
 | 
| 
 | 
  1198 						ch->envPIPValue /= (ins->envPP[envPos][0] - ins->envPP[envPos-1][0]);
 | 
| 
 | 
  1199 
 | 
| 
 | 
  1200 						envVal = ch->envPAmp;
 | 
| 
 | 
  1201 						envDidInterpolate = true;
 | 
| 
 | 
  1202 					}
 | 
| 
 | 
  1203 				}
 | 
| 
 | 
  1204 			}
 | 
| 
 | 
  1205 			else
 | 
| 
 | 
  1206 			{
 | 
| 
 | 
  1207 				ch->envPIPValue = 0;
 | 
| 
 | 
  1208 			}
 | 
| 
 | 
  1209 		}
 | 
| 
 | 
  1210 
 | 
| 
 | 
  1211 		if (!envDidInterpolate)
 | 
| 
 | 
  1212 		{
 | 
| 
 | 
  1213 			ch->envPAmp += ch->envPIPValue;
 | 
| 
 | 
  1214 
 | 
| 
 | 
  1215 			envVal = ch->envPAmp;
 | 
| 
 | 
  1216 			if (envVal > 64*256)
 | 
| 
 | 
  1217 			{
 | 
| 
 | 
  1218 				if (envVal > 128*256)
 | 
| 
 | 
  1219 					envVal = 64*256;
 | 
| 
 | 
  1220 				else
 | 
| 
 | 
  1221 					envVal = 0;
 | 
| 
 | 
  1222 
 | 
| 
 | 
  1223 				ch->envPIPValue = 0;
 | 
| 
 | 
  1224 			}
 | 
| 
 | 
  1225 		}
 | 
| 
 | 
  1226 
 | 
| 
 | 
  1227 		int16_t panTmp = ch->outPan - 128;
 | 
| 
 | 
  1228 		if (panTmp > 0)
 | 
| 
 | 
  1229 			panTmp = 0 - panTmp;
 | 
| 
 | 
  1230 		panTmp += 128;
 | 
| 
 | 
  1231 
 | 
| 
 | 
  1232 		panTmp <<= 3;
 | 
| 
 | 
  1233 		envVal -= 32*256;
 | 
| 
 | 
  1234 
 | 
| 
 | 
  1235 		ch->finalPan = ch->outPan + (uint8_t)(((int16_t)envVal * panTmp) >> 16);
 | 
| 
 | 
  1236 		ch->status |= IS_Pan;
 | 
| 
 | 
  1237 	}
 | 
| 
 | 
  1238 	else
 | 
| 
 | 
  1239 	{
 | 
| 
 | 
  1240 		ch->finalPan = ch->outPan;
 | 
| 
 | 
  1241 	}
 | 
| 
 | 
  1242 
 | 
| 
 | 
  1243 	// *** AUTO VIBRATO ***
 | 
| 
 | 
  1244 	if (ins->vibDepth > 0)
 | 
| 
 | 
  1245 	{
 | 
| 
 | 
  1246 		if (ch->eVibSweep > 0)
 | 
| 
 | 
  1247 		{
 | 
| 
 | 
  1248 			autoVibAmp = ch->eVibSweep;
 | 
| 
 | 
  1249 			if (ch->envSustainActive)
 | 
| 
 | 
  1250 			{
 | 
| 
 | 
  1251 				autoVibAmp += ch->eVibAmp;
 | 
| 
 | 
  1252 				if ((autoVibAmp >> 8) > ins->vibDepth)
 | 
| 
 | 
  1253 				{
 | 
| 
 | 
  1254 					autoVibAmp = ins->vibDepth << 8;
 | 
| 
 | 
  1255 					ch->eVibSweep = 0;
 | 
| 
 | 
  1256 				}
 | 
| 
 | 
  1257 
 | 
| 
 | 
  1258 				ch->eVibAmp = autoVibAmp;
 | 
| 
 | 
  1259 			}
 | 
| 
 | 
  1260 		}
 | 
| 
 | 
  1261 		else
 | 
| 
 | 
  1262 		{
 | 
| 
 | 
  1263 			autoVibAmp = ch->eVibAmp;
 | 
| 
 | 
  1264 		}
 | 
| 
 | 
  1265 
 | 
| 
 | 
  1266 		ch->eVibPos += ins->vibRate;
 | 
| 
 | 
  1267 
 | 
| 
 | 
  1268 		     if (ins->vibTyp == 1) autoVibVal = (ch->eVibPos > 127) ? 64 : -64; // square
 | 
| 
 | 
  1269 		else if (ins->vibTyp == 2) autoVibVal = (((ch->eVibPos >> 1) + 64) & 127) - 64; // ramp up
 | 
| 
 | 
  1270 		else if (ins->vibTyp == 3) autoVibVal = ((-(ch->eVibPos >> 1) + 64) & 127) - 64; // ramp down
 | 
| 
 | 
  1271 		else autoVibVal = vibSineTab[ch->eVibPos]; // sine
 | 
| 
 | 
  1272 
 | 
| 
 | 
  1273 		autoVibVal <<= 2;
 | 
| 
 | 
  1274 		uint16_t tmpPeriod = (autoVibVal * (int16_t)autoVibAmp) >> 16;
 | 
| 
 | 
  1275 
 | 
| 
 | 
  1276 		tmpPeriod += ch->outPeriod;
 | 
| 
 | 
  1277 		if (tmpPeriod >= MAX_FRQ)
 | 
| 
 | 
  1278 			tmpPeriod = 0; // 8bb: yes, FT2 does this (!)
 | 
| 
 | 
  1279 
 | 
| 
 | 
  1280 		ch->finalPeriod = tmpPeriod;
 | 
| 
 | 
  1281 		ch->status |= IS_Period;
 | 
| 
 | 
  1282 	}
 | 
| 
 | 
  1283 	else
 | 
| 
 | 
  1284 	{
 | 
| 
 | 
  1285 		ch->finalPeriod = ch->outPeriod;
 | 
| 
 | 
  1286 	}
 | 
| 
 | 
  1287 }
 | 
| 
 | 
  1288 
 | 
| 
 | 
  1289 // 8bb: converts period to note number, for arpeggio and portamento (in semitone-slide mode)
 | 
| 
 | 
  1290 static uint16_t relocateTon(uint16_t period, uint8_t arpNote, stmTyp *ch)
 | 
| 
 | 
  1291 {
 | 
| 
 | 
  1292 	int32_t tmpPeriod;
 | 
| 
 | 
  1293 
 | 
| 
 | 
  1294 	const int32_t fineTune = ((int8_t)ch->fineTune >> 3) + 16;
 | 
| 
 | 
  1295 	
 | 
| 
 | 
  1296 	/* 8bb: FT2 bug, should've been 10*12*16. Notes above B-7 (95) will have issues.
 | 
| 
 | 
  1297 	** You can only achieve such high notes by having a high relative note value
 | 
| 
 | 
  1298 	** in the sample.
 | 
| 
 | 
  1299 	*/
 | 
| 
 | 
  1300 	int32_t hiPeriod = 8*12*16;
 | 
| 
 | 
  1301 	
 | 
| 
 | 
  1302 	int32_t loPeriod = 0;
 | 
| 
 | 
  1303 
 | 
| 
 | 
  1304 	for (int32_t i = 0; i < 8; i++)
 | 
| 
 | 
  1305 	{
 | 
| 
 | 
  1306 		tmpPeriod = (((loPeriod + hiPeriod) >> 1) & ~15) + fineTune;
 | 
| 
 | 
  1307 
 | 
| 
 | 
  1308 		int32_t lookUp = tmpPeriod - 8;
 | 
| 
 | 
  1309 		if (lookUp < 0)
 | 
| 
 | 
  1310 			lookUp = 0; // 8bb: safety fix (C-0 w/ ftune <= -65). This buggy read seems to return 0 in FT2 (TODO: verify)
 | 
| 
 | 
  1311 
 | 
| 
 | 
  1312 		if (period >= note2Period[lookUp])
 | 
| 
 | 
  1313 			hiPeriod = (tmpPeriod - fineTune) & ~15;
 | 
| 
 | 
  1314 		else
 | 
| 
 | 
  1315 			loPeriod = (tmpPeriod - fineTune) & ~15;
 | 
| 
 | 
  1316 	}
 | 
| 
 | 
  1317 
 | 
| 
 | 
  1318 	tmpPeriod = loPeriod + fineTune + (arpNote << 4);
 | 
| 
 | 
  1319 	if (tmpPeriod >= (8*12*16+15)-1) // 8bb: FT2 bug, should've been 10*12*16+16 (also notice the +2 difference)
 | 
| 
 | 
  1320 		tmpPeriod = (8*12*16+16)-1;
 | 
| 
 | 
  1321 
 | 
| 
 | 
  1322 	return note2Period[tmpPeriod];
 | 
| 
 | 
  1323 }
 | 
| 
 | 
  1324 
 | 
| 
 | 
  1325 static void vibrato2(stmTyp *ch)
 | 
| 
 | 
  1326 {
 | 
| 
 | 
  1327 	uint8_t tmpVib = (ch->vibPos >> 2) & 0x1F;
 | 
| 
 | 
  1328 
 | 
| 
 | 
  1329 	switch (ch->waveCtrl & 3)
 | 
| 
 | 
  1330 	{
 | 
| 
 | 
  1331 		// 0: sine
 | 
| 
 | 
  1332 		case 0: tmpVib = vibTab[tmpVib]; break;
 | 
| 
 | 
  1333 
 | 
| 
 | 
  1334 		// 1: ramp
 | 
| 
 | 
  1335 		case 1:
 | 
| 
 | 
  1336 		{
 | 
| 
 | 
  1337 			tmpVib <<= 3;
 | 
| 
 | 
  1338 			if ((int8_t)ch->vibPos < 0)
 | 
| 
 | 
  1339 				tmpVib = ~tmpVib;
 | 
| 
 | 
  1340 		}
 | 
| 
 | 
  1341 		break;
 | 
| 
 | 
  1342 
 | 
| 
 | 
  1343 		// 2/3: square
 | 
| 
 | 
  1344 		default: tmpVib = 255; break;
 | 
| 
 | 
  1345 	}
 | 
| 
 | 
  1346 
 | 
| 
 | 
  1347 	tmpVib = (tmpVib * ch->vibDepth) >> 5;
 | 
| 
 | 
  1348 
 | 
| 
 | 
  1349 	if ((int8_t)ch->vibPos < 0)
 | 
| 
 | 
  1350 		ch->outPeriod = ch->realPeriod - tmpVib;
 | 
| 
 | 
  1351 	else
 | 
| 
 | 
  1352 		ch->outPeriod = ch->realPeriod + tmpVib;
 | 
| 
 | 
  1353 
 | 
| 
 | 
  1354 	ch->status |= IS_Period;
 | 
| 
 | 
  1355 	ch->vibPos += ch->vibSpeed;
 | 
| 
 | 
  1356 }
 | 
| 
 | 
  1357 
 | 
| 
 | 
  1358 static void arp(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1359 {
 | 
| 
 | 
  1360 	/* 8bb: The original arpTab table only supports 16 ticks, so it can and will overflow.
 | 
| 
 | 
  1361 	** I have added overflown values to the table so that we can handle up to 256 ticks.
 | 
| 
 | 
  1362 	** The added overflow entries are accurate to the overflow-read in FT2.08/FT2.09.
 | 
| 
 | 
  1363 	*/
 | 
| 
 | 
  1364 	const uint8_t tick = arpTab[song.timer & 0xFF];
 | 
| 
 | 
  1365 	
 | 
| 
 | 
  1366 	if (tick == 0)
 | 
| 
 | 
  1367 	{
 | 
| 
 | 
  1368 		ch->outPeriod = ch->realPeriod;
 | 
| 
 | 
  1369 	}
 | 
| 
 | 
  1370 	else
 | 
| 
 | 
  1371 	{
 | 
| 
 | 
  1372 		const uint8_t note = (tick == 1) ? (param >> 4) : (param & 0x0F);
 | 
| 
 | 
  1373 		ch->outPeriod = relocateTon(ch->realPeriod, note, ch);
 | 
| 
 | 
  1374 	}
 | 
| 
 | 
  1375 
 | 
| 
 | 
  1376 	ch->status |= IS_Period;
 | 
| 
 | 
  1377 }
 | 
| 
 | 
  1378 
 | 
| 
 | 
  1379 static void portaUp(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1380 {
 | 
| 
 | 
  1381 	if (param == 0)
 | 
| 
 | 
  1382 		param = ch->portaUpSpeed;
 | 
| 
 | 
  1383 
 | 
| 
 | 
  1384 	ch->portaUpSpeed = param;
 | 
| 
 | 
  1385 
 | 
| 
 | 
  1386 	ch->realPeriod -= param << 2;
 | 
| 
 | 
  1387 	if ((int16_t)ch->realPeriod < 1)
 | 
| 
 | 
  1388 		ch->realPeriod = 1;
 | 
| 
 | 
  1389 
 | 
| 
 | 
  1390 	ch->outPeriod = ch->realPeriod;
 | 
| 
 | 
  1391 	ch->status |= IS_Period;
 | 
| 
 | 
  1392 }
 | 
| 
 | 
  1393 
 | 
| 
 | 
  1394 static void portaDown(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1395 {
 | 
| 
 | 
  1396 	if (param == 0)
 | 
| 
 | 
  1397 		param = ch->portaDownSpeed;
 | 
| 
 | 
  1398 
 | 
| 
 | 
  1399 	ch->portaDownSpeed = param;
 | 
| 
 | 
  1400 
 | 
| 
 | 
  1401 	ch->realPeriod += param << 2;
 | 
| 
 | 
  1402 	if ((int16_t)ch->realPeriod > MAX_FRQ-1) // 8bb: FT2 bug, should've been unsigned comparison!
 | 
| 
 | 
  1403 		ch->realPeriod = MAX_FRQ-1;
 | 
| 
 | 
  1404 
 | 
| 
 | 
  1405 	ch->outPeriod = ch->realPeriod;
 | 
| 
 | 
  1406 	ch->status |= IS_Period;
 | 
| 
 | 
  1407 }
 | 
| 
 | 
  1408 
 | 
| 
 | 
  1409 static void tonePorta(stmTyp *ch, uint8_t param) // 8bb: param is a placeholder (not used)
 | 
| 
 | 
  1410 {
 | 
| 
 | 
  1411 	if (ch->portaDir == 0)
 | 
| 
 | 
  1412 		return;
 | 
| 
 | 
  1413 
 | 
| 
 | 
  1414 	if (ch->portaDir > 1)
 | 
| 
 | 
  1415 	{
 | 
| 
 | 
  1416 		ch->realPeriod -= ch->portaSpeed;
 | 
| 
 | 
  1417 		if ((int16_t)ch->realPeriod <= (int16_t)ch->wantPeriod)
 | 
| 
 | 
  1418 		{
 | 
| 
 | 
  1419 			ch->portaDir = 1;
 | 
| 
 | 
  1420 			ch->realPeriod = ch->wantPeriod;
 | 
| 
 | 
  1421 		}
 | 
| 
 | 
  1422 	}
 | 
| 
 | 
  1423 	else
 | 
| 
 | 
  1424 	{
 | 
| 
 | 
  1425 		ch->realPeriod += ch->portaSpeed;
 | 
| 
 | 
  1426 		if (ch->realPeriod >= ch->wantPeriod)
 | 
| 
 | 
  1427 		{
 | 
| 
 | 
  1428 			ch->portaDir = 1;
 | 
| 
 | 
  1429 			ch->realPeriod = ch->wantPeriod;
 | 
| 
 | 
  1430 		}
 | 
| 
 | 
  1431 	}
 | 
| 
 | 
  1432 
 | 
| 
 | 
  1433 	if (ch->glissFunk) // 8bb: semitone-slide flag
 | 
| 
 | 
  1434 		ch->outPeriod = relocateTon(ch->realPeriod, 0, ch);
 | 
| 
 | 
  1435 	else
 | 
| 
 | 
  1436 		ch->outPeriod = ch->realPeriod;
 | 
| 
 | 
  1437 
 | 
| 
 | 
  1438 	ch->status |= IS_Period;
 | 
| 
 | 
  1439 
 | 
| 
 | 
  1440 	(void)param;
 | 
| 
 | 
  1441 }
 | 
| 
 | 
  1442 
 | 
| 
 | 
  1443 static void vibrato(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1444 {
 | 
| 
 | 
  1445 	uint8_t tmp8;
 | 
| 
 | 
  1446 
 | 
| 
 | 
  1447 	if (ch->eff > 0)
 | 
| 
 | 
  1448 	{
 | 
| 
 | 
  1449 		tmp8 = param & 0x0F;
 | 
| 
 | 
  1450 		if (tmp8 > 0)
 | 
| 
 | 
  1451 			ch->vibDepth = tmp8;
 | 
| 
 | 
  1452 
 | 
| 
 | 
  1453 		tmp8 = (param & 0xF0) >> 2;
 | 
| 
 | 
  1454 		if (tmp8 > 0)
 | 
| 
 | 
  1455 			ch->vibSpeed = tmp8;
 | 
| 
 | 
  1456 	}
 | 
| 
 | 
  1457 
 | 
| 
 | 
  1458 	vibrato2(ch);
 | 
| 
 | 
  1459 }
 | 
| 
 | 
  1460 
 | 
| 
 | 
  1461 static void tonePlusVol(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1462 {
 | 
| 
 | 
  1463 	tonePorta(ch, 0); // 8bb: the last parameter is not used in tonePorta()
 | 
| 
 | 
  1464 	volume(ch, param);
 | 
| 
 | 
  1465 
 | 
| 
 | 
  1466 	(void)param;
 | 
| 
 | 
  1467 }
 | 
| 
 | 
  1468 
 | 
| 
 | 
  1469 static void vibratoPlusVol(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1470 {
 | 
| 
 | 
  1471 	vibrato2(ch);
 | 
| 
 | 
  1472 	volume(ch, param);
 | 
| 
 | 
  1473 
 | 
| 
 | 
  1474 	(void)param;
 | 
| 
 | 
  1475 }
 | 
| 
 | 
  1476 
 | 
| 
 | 
  1477 static void tremolo(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1478 {
 | 
| 
 | 
  1479 	uint8_t tmp8;
 | 
| 
 | 
  1480 	int16_t tremVol;
 | 
| 
 | 
  1481 
 | 
| 
 | 
  1482 	const uint8_t tmpEff = param;
 | 
| 
 | 
  1483 	if (tmpEff > 0)
 | 
| 
 | 
  1484 	{
 | 
| 
 | 
  1485 		tmp8 = tmpEff & 0x0F;
 | 
| 
 | 
  1486 		if (tmp8 > 0)
 | 
| 
 | 
  1487 			ch->tremDepth = tmp8;
 | 
| 
 | 
  1488 
 | 
| 
 | 
  1489 		tmp8 = (tmpEff & 0xF0) >> 2;
 | 
| 
 | 
  1490 		if (tmp8 > 0)
 | 
| 
 | 
  1491 			ch->tremSpeed = tmp8;
 | 
| 
 | 
  1492 	}
 | 
| 
 | 
  1493 
 | 
| 
 | 
  1494 	uint8_t tmpTrem = (ch->tremPos >> 2) & 0x1F;
 | 
| 
 | 
  1495 	switch ((ch->waveCtrl >> 4) & 3)
 | 
| 
 | 
  1496 	{
 | 
| 
 | 
  1497 		// 0: sine
 | 
| 
 | 
  1498 		case 0: tmpTrem = vibTab[tmpTrem]; break;
 | 
| 
 | 
  1499 
 | 
| 
 | 
  1500 		// 1: ramp
 | 
| 
 | 
  1501 		case 1:
 | 
| 
 | 
  1502 		{
 | 
| 
 | 
  1503 			tmpTrem <<= 3;
 | 
| 
 | 
  1504 			if ((int8_t)ch->vibPos < 0) // 8bb: FT2 bug, should've been ch->tremPos
 | 
| 
 | 
  1505 				tmpTrem = ~tmpTrem;
 | 
| 
 | 
  1506 		}
 | 
| 
 | 
  1507 		break;
 | 
| 
 | 
  1508 
 | 
| 
 | 
  1509 		// 2/3: square
 | 
| 
 | 
  1510 		default: tmpTrem = 255; break;
 | 
| 
 | 
  1511 	}
 | 
| 
 | 
  1512 	tmpTrem = (tmpTrem * ch->tremDepth) >> 6;
 | 
| 
 | 
  1513 
 | 
| 
 | 
  1514 	if ((int8_t)ch->tremPos < 0)
 | 
| 
 | 
  1515 	{
 | 
| 
 | 
  1516 		tremVol = ch->realVol - tmpTrem;
 | 
| 
 | 
  1517 		if (tremVol < 0)
 | 
| 
 | 
  1518 			tremVol = 0;
 | 
| 
 | 
  1519 	}
 | 
| 
 | 
  1520 	else
 | 
| 
 | 
  1521 	{
 | 
| 
 | 
  1522 		tremVol = ch->realVol + tmpTrem;
 | 
| 
 | 
  1523 		if (tremVol > 64)
 | 
| 
 | 
  1524 			tremVol = 64;
 | 
| 
 | 
  1525 	}
 | 
| 
 | 
  1526 
 | 
| 
 | 
  1527 	ch->outVol = (uint8_t)tremVol;
 | 
| 
 | 
  1528 	ch->status |= IS_Vol;
 | 
| 
 | 
  1529 	ch->tremPos += ch->tremSpeed;
 | 
| 
 | 
  1530 }
 | 
| 
 | 
  1531 
 | 
| 
 | 
  1532 static void volume(stmTyp *ch, uint8_t param) // 8bb: volume slide
 | 
| 
 | 
  1533 {
 | 
| 
 | 
  1534 	if (param == 0)
 | 
| 
 | 
  1535 		param = ch->volSlideSpeed;
 | 
| 
 | 
  1536 
 | 
| 
 | 
  1537 	ch->volSlideSpeed = param;
 | 
| 
 | 
  1538 
 | 
| 
 | 
  1539 	uint8_t newVol = ch->realVol;
 | 
| 
 | 
  1540 	if ((param & 0xF0) == 0)
 | 
| 
 | 
  1541 	{
 | 
| 
 | 
  1542 		newVol -= param;
 | 
| 
 | 
  1543 		if ((int8_t)newVol < 0)
 | 
| 
 | 
  1544 			newVol = 0;
 | 
| 
 | 
  1545 	}
 | 
| 
 | 
  1546 	else
 | 
| 
 | 
  1547 	{
 | 
| 
 | 
  1548 		param >>= 4;
 | 
| 
 | 
  1549 
 | 
| 
 | 
  1550 		newVol += param;
 | 
| 
 | 
  1551 		if (newVol > 64)
 | 
| 
 | 
  1552 			newVol = 64;
 | 
| 
 | 
  1553 	}
 | 
| 
 | 
  1554 
 | 
| 
 | 
  1555 	ch->outVol = ch->realVol = newVol;
 | 
| 
 | 
  1556 	ch->status |= IS_Vol;
 | 
| 
 | 
  1557 }
 | 
| 
 | 
  1558 
 | 
| 
 | 
  1559 static void globalVolSlide(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1560 {
 | 
| 
 | 
  1561 	if (param == 0)
 | 
| 
 | 
  1562 		param = ch->globVolSlideSpeed;
 | 
| 
 | 
  1563 
 | 
| 
 | 
  1564 	ch->globVolSlideSpeed = param;
 | 
| 
 | 
  1565 
 | 
| 
 | 
  1566 	uint8_t newVol = (uint8_t)song.globVol;
 | 
| 
 | 
  1567 	if ((param & 0xF0) == 0)
 | 
| 
 | 
  1568 	{
 | 
| 
 | 
  1569 		newVol -= param;
 | 
| 
 | 
  1570 		if ((int8_t)newVol < 0)
 | 
| 
 | 
  1571 			newVol = 0;
 | 
| 
 | 
  1572 	}
 | 
| 
 | 
  1573 	else
 | 
| 
 | 
  1574 	{
 | 
| 
 | 
  1575 		param >>= 4;
 | 
| 
 | 
  1576 
 | 
| 
 | 
  1577 		newVol += param;
 | 
| 
 | 
  1578 		if (newVol > 64)
 | 
| 
 | 
  1579 			newVol = 64;
 | 
| 
 | 
  1580 	}
 | 
| 
 | 
  1581 
 | 
| 
 | 
  1582 	song.globVol = newVol;
 | 
| 
 | 
  1583 
 | 
| 
 | 
  1584 	stmTyp *c = stm;
 | 
| 
 | 
  1585 	for (int32_t i = 0; i < song.antChn; i++, c++) // 8bb: this updates the volume for all voices
 | 
| 
 | 
  1586 		c->status |= IS_Vol;
 | 
| 
 | 
  1587 }
 | 
| 
 | 
  1588 
 | 
| 
 | 
  1589 static void keyOffCmd(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1590 {
 | 
| 
 | 
  1591 	if ((uint8_t)(song.tempo-song.timer) == (param & 31))
 | 
| 
 | 
  1592 		keyOff(ch);
 | 
| 
 | 
  1593 }
 | 
| 
 | 
  1594 
 | 
| 
 | 
  1595 static void panningSlide(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1596 {
 | 
| 
 | 
  1597 	if (param == 0)
 | 
| 
 | 
  1598 		param = ch->panningSlideSpeed;
 | 
| 
 | 
  1599 
 | 
| 
 | 
  1600 	ch->panningSlideSpeed = param;
 | 
| 
 | 
  1601 
 | 
| 
 | 
  1602 	int16_t newPan = (int16_t)ch->outPan;
 | 
| 
 | 
  1603 	if ((param & 0xF0) == 0)
 | 
| 
 | 
  1604 	{
 | 
| 
 | 
  1605 		newPan -= param;
 | 
| 
 | 
  1606 		if (newPan < 0)
 | 
| 
 | 
  1607 			newPan = 0;
 | 
| 
 | 
  1608 	}
 | 
| 
 | 
  1609 	else
 | 
| 
 | 
  1610 	{
 | 
| 
 | 
  1611 		param >>= 4;
 | 
| 
 | 
  1612 
 | 
| 
 | 
  1613 		newPan += param;
 | 
| 
 | 
  1614 		if (newPan > 255)
 | 
| 
 | 
  1615 			newPan = 255;
 | 
| 
 | 
  1616 	}
 | 
| 
 | 
  1617 
 | 
| 
 | 
  1618 	ch->outPan = (uint8_t)newPan;
 | 
| 
 | 
  1619 	ch->status |= IS_Pan;
 | 
| 
 | 
  1620 }
 | 
| 
 | 
  1621 
 | 
| 
 | 
  1622 static void tremor(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1623 {
 | 
| 
 | 
  1624 	if (param == 0)
 | 
| 
 | 
  1625 		param = ch->tremorSave;
 | 
| 
 | 
  1626 
 | 
| 
 | 
  1627 	ch->tremorSave = param;
 | 
| 
 | 
  1628 
 | 
| 
 | 
  1629 	uint8_t tremorSign = ch->tremorPos & 0x80;
 | 
| 
 | 
  1630 	uint8_t tremorData = ch->tremorPos & 0x7F;
 | 
| 
 | 
  1631 
 | 
| 
 | 
  1632 	tremorData--;
 | 
| 
 | 
  1633 	if ((int8_t)tremorData < 0)
 | 
| 
 | 
  1634 	{
 | 
| 
 | 
  1635 		if (tremorSign == 0x80)
 | 
| 
 | 
  1636 		{
 | 
| 
 | 
  1637 			tremorSign = 0x00;
 | 
| 
 | 
  1638 			tremorData = param & 0x0F;
 | 
| 
 | 
  1639 		}
 | 
| 
 | 
  1640 		else
 | 
| 
 | 
  1641 		{
 | 
| 
 | 
  1642 			tremorSign = 0x80;
 | 
| 
 | 
  1643 			tremorData = param >> 4;
 | 
| 
 | 
  1644 		}
 | 
| 
 | 
  1645 	}
 | 
| 
 | 
  1646 
 | 
| 
 | 
  1647 	ch->tremorPos = tremorSign | tremorData;
 | 
| 
 | 
  1648 	ch->outVol = (tremorSign == 0x80) ? ch->realVol : 0;
 | 
| 
 | 
  1649 	ch->status |= IS_Vol + IS_QuickVol;
 | 
| 
 | 
  1650 }
 | 
| 
 | 
  1651 
 | 
| 
 | 
  1652 static void retrigNote(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1653 {
 | 
| 
 | 
  1654 	if (param == 0) // 8bb: E9x with a param of zero is handled in getNewNote()
 | 
| 
 | 
  1655 		return;
 | 
| 
 | 
  1656 
 | 
| 
 | 
  1657 	if ((song.tempo-song.timer) % param == 0)
 | 
| 
 | 
  1658 	{
 | 
| 
 | 
  1659 		startTone(0, 0, 0, ch);
 | 
| 
 | 
  1660 		retrigEnvelopeVibrato(ch);
 | 
| 
 | 
  1661 	}
 | 
| 
 | 
  1662 }
 | 
| 
 | 
  1663 
 | 
| 
 | 
  1664 static void noteCut(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1665 {
 | 
| 
 | 
  1666 	if ((uint8_t)(song.tempo-song.timer) == param)
 | 
| 
 | 
  1667 	{
 | 
| 
 | 
  1668 		ch->outVol = ch->realVol = 0;
 | 
| 
 | 
  1669 		ch->status |= IS_Vol + IS_QuickVol;
 | 
| 
 | 
  1670 	}
 | 
| 
 | 
  1671 }
 | 
| 
 | 
  1672 
 | 
| 
 | 
  1673 static void noteDelay(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1674 {
 | 
| 
 | 
  1675 	if ((uint8_t)(song.tempo-song.timer) == param)
 | 
| 
 | 
  1676 	{
 | 
| 
 | 
  1677 		startTone(ch->tonTyp & 0xFF, 0, 0, ch);
 | 
| 
 | 
  1678 
 | 
| 
 | 
  1679 		if ((ch->tonTyp & 0xFF00) > 0) // 8bb: do we have an instrument number?
 | 
| 
 | 
  1680 			retrigVolume(ch);
 | 
| 
 | 
  1681 
 | 
| 
 | 
  1682 		retrigEnvelopeVibrato(ch);
 | 
| 
 | 
  1683 
 | 
| 
 | 
  1684 		if (ch->volKolVol >= 0x10 && ch->volKolVol <= 0x50) // 8bb: Set Volume (volume column)
 | 
| 
 | 
  1685 		{
 | 
| 
 | 
  1686 			ch->outVol = ch->volKolVol - 16;
 | 
| 
 | 
  1687 			ch->realVol = ch->outVol;
 | 
| 
 | 
  1688 		}
 | 
| 
 | 
  1689 		else if (ch->volKolVol >= 0xC0 && ch->volKolVol <= 0xCF) // 8bb: Set Panning (volume column)
 | 
| 
 | 
  1690 		{
 | 
| 
 | 
  1691 			ch->outPan = (ch->volKolVol & 0x0F) << 4;
 | 
| 
 | 
  1692 		}
 | 
| 
 | 
  1693 	}
 | 
| 
 | 
  1694 }
 | 
| 
 | 
  1695 
 | 
| 
 | 
  1696 static const efxRoutine EJumpTab_TickNonZero[16] =
 | 
| 
 | 
  1697 {
 | 
| 
 | 
  1698 	dummy, // 0
 | 
| 
 | 
  1699 	dummy, // 1
 | 
| 
 | 
  1700 	dummy, // 2
 | 
| 
 | 
  1701 	dummy, // 3
 | 
| 
 | 
  1702 	dummy, // 4
 | 
| 
 | 
  1703 	dummy, // 5
 | 
| 
 | 
  1704 	dummy, // 6
 | 
| 
 | 
  1705 	dummy, // 7
 | 
| 
 | 
  1706 	dummy, // 8
 | 
| 
 | 
  1707 	retrigNote, // 9
 | 
| 
 | 
  1708 	dummy, // A
 | 
| 
 | 
  1709 	dummy, // B
 | 
| 
 | 
  1710 	noteCut, // C
 | 
| 
 | 
  1711 	noteDelay, // D
 | 
| 
 | 
  1712 	dummy, // E
 | 
| 
 | 
  1713 	dummy // F
 | 
| 
 | 
  1714 };
 | 
| 
 | 
  1715 
 | 
| 
 | 
  1716 static void E_Effects_TickNonZero(stmTyp *ch, uint8_t param)
 | 
| 
 | 
  1717 {
 | 
| 
 | 
  1718 	EJumpTab_TickNonZero[param >> 4](ch, param & 0xF);
 | 
| 
 | 
  1719 }
 | 
| 
 | 
  1720 
 | 
| 
 | 
  1721 static const efxRoutine JumpTab_TickNonZero[36] =
 | 
| 
 | 
  1722 {
 | 
| 
 | 
  1723 	arp, // 0
 | 
| 
 | 
  1724 	portaUp, // 1
 | 
| 
 | 
  1725 	portaDown, // 2
 | 
| 
 | 
  1726 	tonePorta, // 3
 | 
| 
 | 
  1727 	vibrato, // 4
 | 
| 
 | 
  1728 	tonePlusVol, // 5
 | 
| 
 | 
  1729 	vibratoPlusVol, // 6
 | 
| 
 | 
  1730 	tremolo, // 7
 | 
| 
 | 
  1731 	dummy, // 8
 | 
| 
 | 
  1732 	dummy, // 9
 | 
| 
 | 
  1733 	volume, // A
 | 
| 
 | 
  1734 	dummy, // B
 | 
| 
 | 
  1735 	dummy, // C
 | 
| 
 | 
  1736 	dummy, // D
 | 
| 
 | 
  1737 	E_Effects_TickNonZero, // E
 | 
| 
 | 
  1738 	dummy, // F
 | 
| 
 | 
  1739 	dummy, // G
 | 
| 
 | 
  1740 	globalVolSlide, // H
 | 
| 
 | 
  1741 	dummy, // I
 | 
| 
 | 
  1742 	dummy, // J
 | 
| 
 | 
  1743 	keyOffCmd, // K
 | 
| 
 | 
  1744 	dummy, // L
 | 
| 
 | 
  1745 	dummy, // M
 | 
| 
 | 
  1746 	dummy, // N
 | 
| 
 | 
  1747 	dummy, // O
 | 
| 
 | 
  1748 	panningSlide, // P
 | 
| 
 | 
  1749 	dummy, // Q
 | 
| 
 | 
  1750 	doMultiRetrig, // R
 | 
| 
 | 
  1751 	dummy, // S
 | 
| 
 | 
  1752 	tremor, // T
 | 
| 
 | 
  1753 	dummy, // U
 | 
| 
 | 
  1754 	dummy, // V
 | 
| 
 | 
  1755 	dummy, // W
 | 
| 
 | 
  1756 	dummy, // X
 | 
| 
 | 
  1757 	dummy, // Y
 | 
| 
 | 
  1758 	dummy  // Z
 | 
| 
 | 
  1759 };
 | 
| 
 | 
  1760 
 | 
| 
 | 
  1761 static void doEffects(stmTyp *ch) // tick>0 effect handling
 | 
| 
 | 
  1762 {
 | 
| 
 | 
  1763 	const uint8_t volKolEfx = ch->volKolVol >> 4;
 | 
| 
 | 
  1764 	if (volKolEfx > 0)
 | 
| 
 | 
  1765 		VJumpTab_TickNonZero[volKolEfx](ch);
 | 
| 
 | 
  1766 
 | 
| 
 | 
  1767 	if ((ch->eff == 0 && ch->effTyp == 0) || ch->effTyp > 35)
 | 
| 
 | 
  1768 		return;
 | 
| 
 | 
  1769 
 | 
| 
 | 
  1770 	JumpTab_TickNonZero[ch->effTyp](ch, ch->eff);
 | 
| 
 | 
  1771 }
 | 
| 
 | 
  1772 
 | 
| 
 | 
  1773 static void getNextPos(void)
 | 
| 
 | 
  1774 {
 | 
| 
 | 
  1775 	song.pattPos++;
 | 
| 
 | 
  1776 
 | 
| 
 | 
  1777 	if (song.pattDelTime > 0)
 | 
| 
 | 
  1778 	{
 | 
| 
 | 
  1779 		song.pattDelTime2 = song.pattDelTime;
 | 
| 
 | 
  1780 		song.pattDelTime = 0;
 | 
| 
 | 
  1781 	}
 | 
| 
 | 
  1782 
 | 
| 
 | 
  1783 	if (song.pattDelTime2 > 0)
 | 
| 
 | 
  1784 	{
 | 
| 
 | 
  1785 		song.pattDelTime2--;
 | 
| 
 | 
  1786 		if (song.pattDelTime2 > 0)
 | 
| 
 | 
  1787 			song.pattPos--;
 | 
| 
 | 
  1788 	}
 | 
| 
 | 
  1789 
 | 
| 
 | 
  1790 	if (song.pBreakFlag)
 | 
| 
 | 
  1791 	{
 | 
| 
 | 
  1792 		song.pBreakFlag = false;
 | 
| 
 | 
  1793 		song.pattPos = song.pBreakPos;
 | 
| 
 | 
  1794 	}
 | 
| 
 | 
  1795 
 | 
| 
 | 
  1796 	if (song.pattPos >= song.pattLen || song.posJumpFlag)
 | 
| 
 | 
  1797 	{
 | 
| 
 | 
  1798 		song.pattPos = song.pBreakPos;
 | 
| 
 | 
  1799 		song.pBreakPos = 0;
 | 
| 
 | 
  1800 		song.posJumpFlag = false;
 | 
| 
 | 
  1801 
 | 
| 
 | 
  1802 		song.songPos++;
 | 
| 
 | 
  1803 		if (song.songPos >= song.len)
 | 
| 
 | 
  1804 			song.songPos = song.repS;
 | 
| 
 | 
  1805 
 | 
| 
 | 
  1806 		song.pattNr = song.songTab[(uint8_t)song.songPos];
 | 
| 
 | 
  1807 		song.pattLen = pattLens[(uint8_t)song.pattNr];
 | 
| 
 | 
  1808 	}
 | 
| 
 | 
  1809 }
 | 
| 
 | 
  1810 
 | 
| 
 | 
  1811 void mainPlayer(void)
 | 
| 
 | 
  1812 {
 | 
| 
 | 
  1813 	if (musicPaused)
 | 
| 
 | 
  1814 		return;
 | 
| 
 | 
  1815 
 | 
| 
 | 
  1816 	bool tickZero = false;
 | 
| 
 | 
  1817 
 | 
| 
 | 
  1818 	song.timer--;
 | 
| 
 | 
  1819 	if (song.timer == 0)
 | 
| 
 | 
  1820 	{
 | 
| 
 | 
  1821 		song.timer = song.tempo;
 | 
| 
 | 
  1822 		tickZero = true;
 | 
| 
 | 
  1823 	}
 | 
| 
 | 
  1824 
 | 
| 
 | 
  1825 	const bool readNewNote = tickZero && (song.pattDelTime2 == 0);
 | 
| 
 | 
  1826 	if (readNewNote)
 | 
| 
 | 
  1827 	{
 | 
| 
 | 
  1828 		const tonTyp *pattPtr = nilPatternLine;
 | 
| 
 | 
  1829 		if (patt[song.pattNr] != NULL)
 | 
| 
 | 
  1830 			pattPtr = &patt[song.pattNr][song.pattPos * song.antChn];
 | 
| 
 | 
  1831 
 | 
| 
 | 
  1832 		stmTyp *c = stm;
 | 
| 
 | 
  1833 		for (uint8_t i = 0; i < song.antChn; i++, c++, pattPtr++)
 | 
| 
 | 
  1834 		{
 | 
| 
 | 
  1835 			PMPTmpActiveChannel = i; // 8bb: for P_StartTone()
 | 
| 
 | 
  1836 			getNewNote(c, pattPtr);
 | 
| 
 | 
  1837 			fixaEnvelopeVibrato(c);
 | 
| 
 | 
  1838 		}
 | 
| 
 | 
  1839 	}
 | 
| 
 | 
  1840 	else
 | 
| 
 | 
  1841 	{
 | 
| 
 | 
  1842 		stmTyp *c = stm;
 | 
| 
 | 
  1843 		for (uint8_t i = 0; i < song.antChn; i++, c++)
 | 
| 
 | 
  1844 		{
 | 
| 
 | 
  1845 			PMPTmpActiveChannel = i; // 8bb: for P_StartTone()
 | 
| 
 | 
  1846 			doEffects(c);
 | 
| 
 | 
  1847 			fixaEnvelopeVibrato(c);
 | 
| 
 | 
  1848 		}
 | 
| 
 | 
  1849 	}
 | 
| 
 | 
  1850 
 | 
| 
 | 
  1851 	if (song.timer == 1)
 | 
| 
 | 
  1852 		getNextPos();
 | 
| 
 | 
  1853 }
 |