1 /*
2  * Sndmix.cpp
3  * -----------
4  * Purpose: Pattern playback, effect processing
5  * Notes  : (currently none)
6  * Authors: Olivier Lapicque
7  *          OpenMPT Devs
8  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
9  */
10 
11 
12 #include "stdafx.h"
13 
14 #include "Sndfile.h"
15 #include "MixerLoops.h"
16 #include "MIDIEvents.h"
17 #include "Tables.h"
18 #ifdef MODPLUG_TRACKER
19 #include "../mptrack/TrackerSettings.h"
20 #endif // MODPLUG_TRACKER
21 #ifndef NO_PLUGINS
22 #include "plugins/PlugInterface.h"
23 #endif // NO_PLUGINS
24 #include "OPL.h"
25 
26 OPENMPT_NAMESPACE_BEGIN
27 
28 // Log tables for pre-amp
29 // Pre-amp (or more precisely: Pre-attenuation) depends on the number of channels,
30 // Which this table takes care of.
31 static constexpr uint8 PreAmpTable[16] =
32 {
33 	0x60, 0x60, 0x60, 0x70,	// 0-7
34 	0x80, 0x88, 0x90, 0x98,	// 8-15
35 	0xA0, 0xA4, 0xA8, 0xAC,	// 16-23
36 	0xB0, 0xB4, 0xB8, 0xBC,	// 24-31
37 };
38 
39 #ifndef NO_AGC
40 static constexpr uint8 PreAmpAGCTable[16] =
41 {
42 	0x60, 0x60, 0x60, 0x64,
43 	0x68, 0x70, 0x78, 0x80,
44 	0x84, 0x88, 0x8C, 0x90,
45 	0x92, 0x94, 0x96, 0x98,
46 };
47 #endif
48 
49 
SetMixerSettings(const MixerSettings & mixersettings)50 void CSoundFile::SetMixerSettings(const MixerSettings &mixersettings)
51 {
52 	SetPreAmp(mixersettings.m_nPreAmp); // adjust agc
53 	bool reset = false;
54 	if(
55 		(mixersettings.gdwMixingFreq != m_MixerSettings.gdwMixingFreq)
56 		||
57 		(mixersettings.gnChannels != m_MixerSettings.gnChannels)
58 		||
59 		(mixersettings.MixerFlags != m_MixerSettings.MixerFlags))
60 		reset = true;
61 	m_MixerSettings = mixersettings;
62 	InitPlayer(reset);
63 }
64 
65 
SetResamplerSettings(const CResamplerSettings & resamplersettings)66 void CSoundFile::SetResamplerSettings(const CResamplerSettings &resamplersettings)
67 {
68 	m_Resampler.m_Settings = resamplersettings;
69 	m_Resampler.UpdateTables();
70 	InitAmigaResampler();
71 }
72 
73 
InitPlayer(bool bReset)74 void CSoundFile::InitPlayer(bool bReset)
75 {
76 	if(bReset)
77 	{
78 		ResetMixStat();
79 		m_dryLOfsVol = m_dryROfsVol = 0;
80 		m_surroundLOfsVol = m_surroundROfsVol = 0;
81 		InitAmigaResampler();
82 	}
83 	m_Resampler.UpdateTables();
84 #ifndef NO_REVERB
85 	m_Reverb.Initialize(bReset, m_RvbROfsVol, m_RvbLOfsVol, m_MixerSettings.gdwMixingFreq);
86 #endif
87 #ifndef NO_DSP
88 	m_Surround.Initialize(bReset, m_MixerSettings.gdwMixingFreq);
89 #endif
90 #ifndef NO_DSP
91 	m_MegaBass.Initialize(bReset, m_MixerSettings.gdwMixingFreq);
92 #endif
93 #ifndef NO_EQ
94 	m_EQ.Initialize(bReset, m_MixerSettings.gdwMixingFreq);
95 #endif
96 #ifndef NO_AGC
97 	m_AGC.Initialize(bReset, m_MixerSettings.gdwMixingFreq);
98 #endif
99 #ifndef NO_DSP
100 	m_BitCrush.Initialize(bReset, m_MixerSettings.gdwMixingFreq);
101 #endif
102 	if(m_opl)
103 	{
104 		m_opl->Initialize(m_MixerSettings.gdwMixingFreq);
105 	}
106 }
107 
108 
FadeSong(uint32 msec)109 bool CSoundFile::FadeSong(uint32 msec)
110 {
111 	samplecount_t nsamples = Util::muldiv(msec, m_MixerSettings.gdwMixingFreq, 1000);
112 	if (nsamples <= 0) return false;
113 	if (nsamples > 0x100000) nsamples = 0x100000;
114 	m_PlayState.m_nBufferCount = nsamples;
115 	int32 nRampLength = static_cast<int32>(m_PlayState.m_nBufferCount);
116 	// Ramp everything down
117 	for (uint32 noff=0; noff < m_nMixChannels; noff++)
118 	{
119 		ModChannel &pramp = m_PlayState.Chn[m_PlayState.ChnMix[noff]];
120 		pramp.newRightVol = pramp.newLeftVol = 0;
121 		pramp.leftRamp = -pramp.leftVol * (1 << VOLUMERAMPPRECISION) / nRampLength;
122 		pramp.rightRamp = -pramp.rightVol * (1 << VOLUMERAMPPRECISION) / nRampLength;
123 		pramp.rampLeftVol = pramp.leftVol * (1 << VOLUMERAMPPRECISION);
124 		pramp.rampRightVol = pramp.rightVol * (1 << VOLUMERAMPPRECISION);
125 		pramp.nRampLength = nRampLength;
126 		pramp.dwFlags.set(CHN_VOLUMERAMP);
127 	}
128 	return true;
129 }
130 
131 
132 // Apply stereo separation factor on an interleaved stereo/quad stream.
133 // count = Number of stereo sample pairs to process
134 // separation = -256...256 (negative values = swap L/R, 0 = mono, 128 = normal)
ApplyStereoSeparation(mixsample_t * mixBuf,std::size_t count,int32 separation)135 static void ApplyStereoSeparation(mixsample_t *mixBuf, std::size_t count, int32 separation)
136 {
137 #ifdef MPT_INTMIXER
138 	const mixsample_t factor_num = separation; // 128 =^= 1.0f
139 	const mixsample_t factor_den = MixerSettings::StereoSeparationScale; // 128
140 	const mixsample_t normalize_den = 2; // mid/side pre/post normalization
141 	const mixsample_t mid_den = normalize_den;
142 	const mixsample_t side_num = factor_num;
143 	const mixsample_t side_den = factor_den * normalize_den;
144 #else
145 	const float normalize_factor = 0.5f; // cumulative mid/side normalization factor (1/sqrt(2))*(1/sqrt(2))
146 	const float factor = static_cast<float>(separation) / static_cast<float>(MixerSettings::StereoSeparationScale); // sep / 128
147 	const float mid_factor = normalize_factor;
148 	const float side_factor = factor * normalize_factor;
149 #endif
150 	for(std::size_t i = 0; i < count; i++)
151 	{
152 		mixsample_t l = mixBuf[0];
153 		mixsample_t r = mixBuf[1];
154 		mixsample_t m = l + r;
155 		mixsample_t s = l - r;
156 #ifdef MPT_INTMIXER
157 		m /= mid_den;
158 		s = Util::muldiv(s, side_num, side_den);
159 #else
160 		m *= mid_factor;
161 		s *= side_factor;
162 #endif
163 		l = m + s;
164 		r = m - s;
165 		mixBuf[0] = l;
166 		mixBuf[1] = r;
167 		mixBuf += 2;
168 	}
169 }
170 
171 
ApplyStereoSeparation(mixsample_t * SoundFrontBuffer,mixsample_t * SoundRearBuffer,std::size_t channels,std::size_t countChunk,int32 separation)172 static void ApplyStereoSeparation(mixsample_t *SoundFrontBuffer, mixsample_t *SoundRearBuffer, std::size_t channels, std::size_t countChunk, int32 separation)
173 {
174 	if(separation == MixerSettings::StereoSeparationScale)
175 	{ // identity
176 		return;
177 	}
178 	if(channels >= 2) ApplyStereoSeparation(SoundFrontBuffer, countChunk, separation);
179 	if(channels >= 4) ApplyStereoSeparation(SoundRearBuffer , countChunk, separation);
180 }
181 
182 
ProcessInputChannels(IAudioSource & source,std::size_t countChunk)183 void CSoundFile::ProcessInputChannels(IAudioSource &source, std::size_t countChunk)
184 {
185 	for(std::size_t channel = 0; channel < NUMMIXINPUTBUFFERS; ++channel)
186 	{
187 		std::fill(&(MixInputBuffer[channel][0]), &(MixInputBuffer[channel][countChunk]), 0);
188 	}
189 	mixsample_t * buffers[NUMMIXINPUTBUFFERS];
190 	for(std::size_t channel = 0; channel < NUMMIXINPUTBUFFERS; ++channel)
191 	{
192 		buffers[channel] = MixInputBuffer[channel];
193 	}
194 	source.Process(mpt::audio_span_planar(buffers, m_MixerSettings.NumInputChannels, countChunk));
195 }
196 
197 
198 // Read one tick but skip all expensive rendering options
ReadOneTick()199 CSoundFile::samplecount_t CSoundFile::ReadOneTick()
200 {
201 	const auto origMaxMixChannels = m_MixerSettings.m_nMaxMixChannels;
202 	m_MixerSettings.m_nMaxMixChannels = 0;
203 	while(m_PlayState.m_nBufferCount)
204 	{
205 		auto framesToRender = std::min(m_PlayState.m_nBufferCount, samplecount_t(MIXBUFFERSIZE));
206 		CreateStereoMix(framesToRender);
207 		m_PlayState.m_nBufferCount -= framesToRender;
208 		m_PlayState.m_lTotalSampleCount += framesToRender;
209 	}
210 	m_MixerSettings.m_nMaxMixChannels = origMaxMixChannels;
211 	if(ReadNote())
212 		return m_PlayState.m_nBufferCount;
213 	else
214 		return 0;
215 }
216 
217 
Read(samplecount_t count,IAudioTarget & target,IAudioSource & source,std::optional<std::reference_wrapper<IMonitorOutput>> outputMonitor,std::optional<std::reference_wrapper<IMonitorInput>> inputMonitor)218 CSoundFile::samplecount_t CSoundFile::Read(samplecount_t count, IAudioTarget &target, IAudioSource &source, std::optional<std::reference_wrapper<IMonitorOutput>> outputMonitor, std::optional<std::reference_wrapper<IMonitorInput>> inputMonitor)
219 {
220 	MPT_ASSERT_ALWAYS(m_MixerSettings.IsValid());
221 
222 	samplecount_t countRendered = 0;
223 	samplecount_t countToRender = count;
224 
225 	while(!m_SongFlags[SONG_ENDREACHED] && countToRender > 0)
226 	{
227 
228 		// Update Channel Data
229 		if(!m_PlayState.m_nBufferCount)
230 		{
231 			// Last tick or fade completely processed, find out what to do next
232 
233 			if(m_SongFlags[SONG_FADINGSONG])
234 			{
235 				// Song was faded out
236 				m_SongFlags.set(SONG_ENDREACHED);
237 			} else if(ReadNote())
238 			{
239 				// Render next tick (normal progress)
240 				MPT_ASSERT(m_PlayState.m_nBufferCount > 0);
241 				#ifdef MODPLUG_TRACKER
242 					// Save pattern cue points for WAV rendering here (if we reached a new pattern, that is.)
243 					if(m_PatternCuePoints != nullptr && (m_PatternCuePoints->empty() || m_PlayState.m_nCurrentOrder != m_PatternCuePoints->back().order))
244 					{
245 						PatternCuePoint cue;
246 						cue.offset = countRendered;
247 						cue.order = m_PlayState.m_nCurrentOrder;
248 						cue.processed = false;	// We don't know the base offset in the file here. It has to be added in the main conversion loop.
249 						m_PatternCuePoints->push_back(cue);
250 					}
251 				#endif
252 			} else
253 			{
254 				// No new pattern data
255 				#ifdef MODPLUG_TRACKER
256 					if((m_nMaxOrderPosition) && (m_PlayState.m_nCurrentOrder >= m_nMaxOrderPosition))
257 					{
258 						m_SongFlags.set(SONG_ENDREACHED);
259 					}
260 				#endif // MODPLUG_TRACKER
261 				if(IsRenderingToDisc())
262 				{
263 					// Disable song fade when rendering or when requested in libopenmpt.
264 					m_SongFlags.set(SONG_ENDREACHED);
265 				} else
266 				{ // end of song reached, fade it out
267 					if(FadeSong(FADESONGDELAY)) // sets m_nBufferCount xor returns false
268 					{ // FadeSong sets m_nBufferCount here
269 						MPT_ASSERT(m_PlayState.m_nBufferCount > 0);
270 						m_SongFlags.set(SONG_FADINGSONG);
271 					} else
272 					{
273 						m_SongFlags.set(SONG_ENDREACHED);
274 					}
275 				}
276 			}
277 
278 		}
279 
280 		if(m_SongFlags[SONG_ENDREACHED])
281 		{
282 			// Mix done.
283 
284 			// If we decide to continue the mix (possible in libopenmpt), the tick count
285 			// is valid right now (0), meaning that no new row data will be processed.
286 			// This would effectively prolong the last played row.
287 			m_PlayState.m_nTickCount = m_PlayState.TicksOnRow();
288 			break;
289 		}
290 
291 		MPT_ASSERT(m_PlayState.m_nBufferCount > 0); // assert that we have actually something to do
292 
293 		const samplecount_t countChunk = std::min({ static_cast<samplecount_t>(MIXBUFFERSIZE), static_cast<samplecount_t>(m_PlayState.m_nBufferCount), static_cast<samplecount_t>(countToRender) });
294 
295 		if(m_MixerSettings.NumInputChannels > 0)
296 		{
297 			ProcessInputChannels(source, countChunk);
298 		}
299 
300 		if(inputMonitor)
301 		{
302 			mixsample_t *buffers[NUMMIXINPUTBUFFERS];
303 			for(std::size_t channel = 0; channel < NUMMIXINPUTBUFFERS; ++channel)
304 			{
305 				buffers[channel] = MixInputBuffer[channel];
306 			}
307 			inputMonitor->get().Process(mpt::audio_span_planar<const mixsample_t>(buffers, m_MixerSettings.NumInputChannels, countChunk));
308 		}
309 
310 		CreateStereoMix(countChunk);
311 
312 		if(m_opl)
313 		{
314 			m_opl->Mix(MixSoundBuffer, countChunk, m_OPLVolumeFactor * m_nVSTiVolume / 48);
315 		}
316 
317 #ifndef NO_REVERB
318 		m_Reverb.Process(MixSoundBuffer, ReverbSendBuffer, m_RvbROfsVol, m_RvbLOfsVol, countChunk);
319 #endif  // NO_REVERB
320 
321 #ifndef NO_PLUGINS
322 		if(m_loadedPlugins)
323 		{
324 			ProcessPlugins(countChunk);
325 		}
326 #endif  // NO_PLUGINS
327 
328 		if(m_MixerSettings.gnChannels == 1)
329 		{
330 			MonoFromStereo(MixSoundBuffer, countChunk);
331 		}
332 
333 		if(m_PlayConfig.getGlobalVolumeAppliesToMaster())
334 		{
335 			ProcessGlobalVolume(countChunk);
336 		}
337 
338 		if(m_MixerSettings.m_nStereoSeparation != MixerSettings::StereoSeparationScale)
339 		{
340 			ProcessStereoSeparation(countChunk);
341 		}
342 
343 		if(m_MixerSettings.DSPMask)
344 		{
345 			ProcessDSP(countChunk);
346 		}
347 
348 		if(m_MixerSettings.gnChannels == 4)
349 		{
350 			InterleaveFrontRear(MixSoundBuffer, MixRearBuffer, countChunk);
351 		}
352 
353 		if(outputMonitor)
354 		{
355 			outputMonitor->get().Process(mpt::audio_span_interleaved<const mixsample_t>(MixSoundBuffer, m_MixerSettings.gnChannels, countChunk));
356 		}
357 
358 		target.Process(mpt::audio_span_interleaved<mixsample_t>(MixSoundBuffer, m_MixerSettings.gnChannels, countChunk));
359 
360 		// Buffer ready
361 		countRendered += countChunk;
362 		countToRender -= countChunk;
363 		m_PlayState.m_nBufferCount -= countChunk;
364 		m_PlayState.m_lTotalSampleCount += countChunk;
365 
366 #ifdef MODPLUG_TRACKER
367 		if(IsRenderingToDisc())
368 		{
369 			// Stop playback on F00 if no more voices are active.
370 			// F00 sets the tick count to 65536 in FT2, so it just generates a reaaaally long row.
371 			// Usually this command can be found at the end of a song to effectively stop playback.
372 			// Since we don't want to render hours of silence, we are going to check if there are
373 			// still any channels playing, and if that is no longer the case, we stop playback at
374 			// the end of the next tick.
375 			if(m_PlayState.m_nMusicSpeed == uint16_max && (m_nMixStat == 0 || m_PlayState.m_nGlobalVolume == 0) && GetType() == MOD_TYPE_XM && !m_PlayState.m_nBufferCount)
376 			{
377 				m_SongFlags.set(SONG_ENDREACHED);
378 			}
379 		}
380 #endif // MODPLUG_TRACKER
381 	}
382 
383 	// mix done
384 
385 	return countRendered;
386 
387 }
388 
389 
ProcessDSP(uint32 countChunk)390 void CSoundFile::ProcessDSP(uint32 countChunk)
391 {
392 	#ifndef NO_DSP
393 		if(m_MixerSettings.DSPMask & SNDDSP_SURROUND)
394 		{
395 			m_Surround.Process(MixSoundBuffer, MixRearBuffer, countChunk, m_MixerSettings.gnChannels);
396 		}
397 	#endif // NO_DSP
398 
399 	#ifndef NO_DSP
400 		if(m_MixerSettings.DSPMask & SNDDSP_MEGABASS)
401 		{
402 			m_MegaBass.Process(MixSoundBuffer, MixRearBuffer, countChunk, m_MixerSettings.gnChannels);
403 		}
404 	#endif // NO_DSP
405 
406 	#ifndef NO_EQ
407 		if(m_MixerSettings.DSPMask & SNDDSP_EQ)
408 		{
409 			m_EQ.Process(MixSoundBuffer, MixRearBuffer, countChunk, m_MixerSettings.gnChannels);
410 		}
411 	#endif // NO_EQ
412 
413 	#ifndef NO_AGC
414 		if(m_MixerSettings.DSPMask & SNDDSP_AGC)
415 		{
416 			m_AGC.Process(MixSoundBuffer, MixRearBuffer, countChunk, m_MixerSettings.gnChannels);
417 		}
418 	#endif // NO_AGC
419 
420 	#ifndef NO_DSP
421 		if(m_MixerSettings.DSPMask & SNDDSP_BITCRUSH)
422 		{
423 			m_BitCrush.Process(MixSoundBuffer, MixRearBuffer, countChunk, m_MixerSettings.gnChannels);
424 		}
425 	#endif // NO_DSP
426 
427 	#if defined(NO_DSP) && defined(NO_EQ) && defined(NO_AGC)
428 		MPT_UNREFERENCED_PARAMETER(countChunk);
429 	#endif
430 }
431 
432 
433 /////////////////////////////////////////////////////////////////////////////
434 // Handles navigation/effects
435 
ProcessRow()436 bool CSoundFile::ProcessRow()
437 {
438 	while(++m_PlayState.m_nTickCount >= m_PlayState.TicksOnRow())
439 	{
440 		const auto [ignoreRow, patternTransition] = NextRow(m_PlayState, m_SongFlags[SONG_BREAKTOROW]);
441 
442 #ifdef MODPLUG_TRACKER
443 		if(patternTransition)
444 		{
445 			HandlePatternTransitionEvents();
446 		}
447 		// "Lock row" editing feature
448 		if(m_lockRowStart != ROWINDEX_INVALID && (m_PlayState.m_nRow < m_lockRowStart || m_PlayState.m_nRow > m_lockRowEnd) && !IsRenderingToDisc())
449 		{
450 			m_PlayState.m_nRow = m_lockRowStart;
451 		}
452 		// "Lock order" editing feature
453 		if(Order().IsPositionLocked(m_PlayState.m_nCurrentOrder) && !IsRenderingToDisc())
454 		{
455 			m_PlayState.m_nCurrentOrder = m_lockOrderStart;
456 		}
457 #else
458 		MPT_UNUSED_VARIABLE(patternTransition);
459 #endif // MODPLUG_TRACKER
460 
461 		// Check if pattern is valid
462 		if(!m_SongFlags[SONG_PATTERNLOOP])
463 		{
464 			m_PlayState.m_nPattern = (m_PlayState.m_nCurrentOrder < Order().size()) ? Order()[m_PlayState.m_nCurrentOrder] : Order.GetInvalidPatIndex();
465 			if (m_PlayState.m_nPattern < Patterns.Size() && !Patterns[m_PlayState.m_nPattern].IsValid()) m_PlayState.m_nPattern = Order.GetIgnoreIndex();
466 			while (m_PlayState.m_nPattern >= Patterns.Size())
467 			{
468 				// End of song?
469 				if ((m_PlayState.m_nPattern == Order.GetInvalidPatIndex()) || (m_PlayState.m_nCurrentOrder >= Order().size()))
470 				{
471 					ORDERINDEX restartPosOverride = Order().GetRestartPos();
472 					if(restartPosOverride == 0 && m_PlayState.m_nCurrentOrder <= Order().size() && m_PlayState.m_nCurrentOrder > 0)
473 					{
474 						// Subtune detection. Subtunes are separated by "---" order items, so if we're in a
475 						// subtune and there's no restart position, we go to the first order of the subtune
476 						// (i.e. the first order after the previous "---" item)
477 						for(ORDERINDEX ord = m_PlayState.m_nCurrentOrder - 1; ord > 0; ord--)
478 						{
479 							if(Order()[ord] == Order.GetInvalidPatIndex())
480 							{
481 								// Jump back to first order of this subtune
482 								restartPosOverride = ord + 1;
483 								break;
484 							}
485 						}
486 					}
487 
488 					// If channel resetting is disabled in MPT, we will emulate a pattern break (and we always do it if we're not in MPT)
489 #ifdef MODPLUG_TRACKER
490 					if(!(TrackerSettings::Instance().m_dwPatternSetup & PATTERN_RESETCHANNELS))
491 #endif // MODPLUG_TRACKER
492 					{
493 						m_SongFlags.set(SONG_BREAKTOROW);
494 					}
495 
496 					if (restartPosOverride == 0 && !m_SongFlags[SONG_BREAKTOROW])
497 					{
498 						//rewbs.instroVSTi: stop all VSTi at end of song, if looping.
499 						StopAllVsti();
500 						m_PlayState.m_nMusicSpeed = m_nDefaultSpeed;
501 						m_PlayState.m_nMusicTempo = m_nDefaultTempo;
502 						m_PlayState.m_nGlobalVolume = m_nDefaultGlobalVolume;
503 						for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
504 						{
505 							auto &chn = m_PlayState.Chn[i];
506 							if(chn.dwFlags[CHN_ADLIB] && m_opl)
507 							{
508 								m_opl->NoteCut(i);
509 							}
510 							chn.dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF);
511 							chn.nFadeOutVol = 0;
512 
513 							if(i < m_nChannels)
514 							{
515 								chn.nGlobalVol = ChnSettings[i].nVolume;
516 								chn.nVolume = ChnSettings[i].nVolume;
517 								chn.nPan = ChnSettings[i].nPan;
518 								chn.nPanSwing = chn.nVolSwing = 0;
519 								chn.nCutSwing = chn.nResSwing = 0;
520 								chn.nOldVolParam = 0;
521 								chn.oldOffset = 0;
522 								chn.nOldHiOffset = 0;
523 								chn.nPortamentoDest = 0;
524 
525 								if(!chn.nLength)
526 								{
527 									chn.dwFlags = ChnSettings[i].dwFlags;
528 									chn.nLoopStart = 0;
529 									chn.nLoopEnd = 0;
530 									chn.pModInstrument = nullptr;
531 									chn.pModSample = nullptr;
532 								}
533 							}
534 						}
535 					}
536 
537 					//Handle Repeat position
538 					m_PlayState.m_nCurrentOrder = restartPosOverride;
539 					m_SongFlags.reset(SONG_BREAKTOROW);
540 					//If restart pos points to +++, move along
541 					while(m_PlayState.m_nCurrentOrder < Order().size() && Order()[m_PlayState.m_nCurrentOrder] == Order.GetIgnoreIndex())
542 					{
543 						m_PlayState.m_nCurrentOrder++;
544 					}
545 					//Check for end of song or bad pattern
546 					if (m_PlayState.m_nCurrentOrder >= Order().size()
547 						|| !Order().IsValidPat(m_PlayState.m_nCurrentOrder))
548 					{
549 						m_visitedRows.Initialize(true);
550 						return false;
551 					}
552 				} else
553 				{
554 					m_PlayState.m_nCurrentOrder++;
555 				}
556 
557 				if (m_PlayState.m_nCurrentOrder < Order().size())
558 					m_PlayState.m_nPattern = Order()[m_PlayState.m_nCurrentOrder];
559 				else
560 					m_PlayState.m_nPattern = Order.GetInvalidPatIndex();
561 
562 				if (m_PlayState.m_nPattern < Patterns.Size() && !Patterns[m_PlayState.m_nPattern].IsValid())
563 					m_PlayState.m_nPattern = Order.GetIgnoreIndex();
564 			}
565 			m_PlayState.m_nNextOrder = m_PlayState.m_nCurrentOrder;
566 
567 #ifdef MODPLUG_TRACKER
568 			if ((m_nMaxOrderPosition) && (m_PlayState.m_nCurrentOrder >= m_nMaxOrderPosition)) return false;
569 #endif // MODPLUG_TRACKER
570 		}
571 
572 		// Weird stuff?
573 		if (!Patterns.IsValidPat(m_PlayState.m_nPattern))
574 			return false;
575 		// Did we jump to an invalid row?
576 		if (m_PlayState.m_nRow >= Patterns[m_PlayState.m_nPattern].GetNumRows()) m_PlayState.m_nRow = 0;
577 
578 		// Has this row been visited before? We might want to stop playback now.
579 		// But: We will not mark the row as modified if the song is not in loop mode but
580 		// the pattern loop (editor flag, not to be confused with the pattern loop effect)
581 		// flag is set - because in that case, the module would stop after the first pattern loop...
582 		const bool overrideLoopCheck = (m_nRepeatCount != -1) && m_SongFlags[SONG_PATTERNLOOP];
583 		if(!overrideLoopCheck && m_visitedRows.Visit(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow, m_PlayState.Chn, ignoreRow))
584 		{
585 			if(m_nRepeatCount)
586 			{
587 				// repeat count == -1 means repeat infinitely.
588 				if(m_nRepeatCount > 0)
589 				{
590 					m_nRepeatCount--;
591 				}
592 				// Forget all but the current row.
593 				m_visitedRows.Initialize(true);
594 				m_visitedRows.Visit(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow, m_PlayState.Chn, ignoreRow);
595 			} else
596 			{
597 #ifdef MODPLUG_TRACKER
598 				// Let's check again if this really is the end of the song.
599 				// The visited rows vector might have been screwed up while editing...
600 				// This is of course not possible during rendering to WAV, so we ignore that case.
601 				bool isReallyAtEnd = IsRenderingToDisc();
602 				if(!isReallyAtEnd)
603 				{
604 					for(const auto &t : GetLength(eNoAdjust, GetLengthTarget(true)))
605 					{
606 						if(t.lastOrder == m_PlayState.m_nCurrentOrder && t.lastRow == m_PlayState.m_nRow)
607 						{
608 							isReallyAtEnd = true;
609 							break;
610 						}
611 					}
612 				}
613 
614 				if(isReallyAtEnd)
615 				{
616 					// This is really the song's end!
617 					m_visitedRows.Initialize(true);
618 					return false;
619 				} else
620 				{
621 					// Ok, this is really dirty, but we have to update the visited rows vector...
622 					GetLength(eAdjustOnlyVisitedRows, GetLengthTarget(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow));
623 				}
624 #else
625 				if(m_SongFlags[SONG_PLAYALLSONGS])
626 				{
627 					// When playing all subsongs consecutively, first search for any hidden subsongs...
628 					if(!m_visitedRows.GetFirstUnvisitedRow(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow, true))
629 					{
630 						// ...and then try the next sequence.
631 						m_PlayState.m_nNextOrder = m_PlayState.m_nCurrentOrder = 0;
632 						m_PlayState.m_nNextRow = m_PlayState.m_nRow = 0;
633 						if(Order.GetCurrentSequenceIndex() >= Order.GetNumSequences() - 1)
634 						{
635 							Order.SetSequence(0);
636 							m_visitedRows.Initialize(true);
637 							return false;
638 						}
639 						Order.SetSequence(Order.GetCurrentSequenceIndex() + 1);
640 						m_visitedRows.Initialize(true);
641 					}
642 					// When jumping to the next subsong, stop all playing notes from the previous song...
643 					const auto muteFlag = CSoundFile::GetChannelMuteFlag();
644 					for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
645 						m_PlayState.Chn[i].Reset(ModChannel::resetSetPosFull, *this, i, muteFlag);
646 					StopAllVsti();
647 					// ...and the global playback information.
648 					m_PlayState.m_nMusicSpeed = m_nDefaultSpeed;
649 					m_PlayState.m_nMusicTempo = m_nDefaultTempo;
650 					m_PlayState.m_nGlobalVolume = m_nDefaultGlobalVolume;
651 
652 					m_PlayState.m_nNextOrder = m_PlayState.m_nCurrentOrder;
653 					m_PlayState.m_nNextRow = m_PlayState.m_nRow;
654 					if(Order().size() > m_PlayState.m_nCurrentOrder)
655 						m_PlayState.m_nPattern = Order()[m_PlayState.m_nCurrentOrder];
656 					m_visitedRows.Visit(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow, m_PlayState.Chn, ignoreRow);
657 					if (!Patterns.IsValidPat(m_PlayState.m_nPattern))
658 						return false;
659 				} else
660 				{
661 					m_visitedRows.Initialize(true);
662 					return false;
663 				}
664 #endif // MODPLUG_TRACKER
665 			}
666 		}
667 
668 		SetupNextRow(m_PlayState, m_SongFlags[SONG_PATTERNLOOP]);
669 
670 		// Reset channel values
671 		ModCommand *m = Patterns[m_PlayState.m_nPattern].GetpModCommand(m_PlayState.m_nRow, 0);
672 		for (ModChannel *pChn = m_PlayState.Chn, *pEnd = pChn + m_nChannels; pChn != pEnd; pChn++, m++)
673 		{
674 			// First, handle some quirks that happen after the last tick of the previous row...
675 			if(m_playBehaviour[KST3PortaAfterArpeggio]
676 				&& pChn->nCommand == CMD_ARPEGGIO	// Previous row state!
677 				&& (m->command == CMD_PORTAMENTOUP || m->command == CMD_PORTAMENTODOWN))
678 			{
679 				// In ST3, a portamento immediately following an arpeggio continues where the arpeggio left off.
680 				// Test case: PortaAfterArp.s3m
681 				pChn->nPeriod = GetPeriodFromNote(pChn->nArpeggioLastNote, pChn->nFineTune, pChn->nC5Speed);
682 			}
683 
684 			if(m_playBehaviour[kMODOutOfRangeNoteDelay]
685 				&& !m->IsNote()
686 				&& pChn->rowCommand.IsNote()
687 				&& pChn->rowCommand.command == CMD_MODCMDEX && (pChn->rowCommand.param & 0xF0) == 0xD0
688 				&& (pChn->rowCommand.param & 0x0Fu) >= m_PlayState.m_nMusicSpeed)
689 			{
690 				// In ProTracker, a note triggered by an out-of-range note delay can be heard on the next row
691 				// if there is no new note on that row.
692 				// Test case: NoteDelay-NextRow.mod
693 				pChn->nPeriod = GetPeriodFromNote(pChn->rowCommand.note, pChn->nFineTune, 0);
694 			}
695 			if(m_playBehaviour[kMODTempoOnSecondTick] && !m_playBehaviour[kMODVBlankTiming] && m_PlayState.m_nMusicSpeed == 1 && pChn->rowCommand.command == CMD_TEMPO)
696 			{
697 				// ProTracker sets the tempo after the first tick. This block handles the case of one tick per row.
698 				// Test case: TempoChange.mod
699 				m_PlayState.m_nMusicTempo = TEMPO(pChn->rowCommand.param, 0);
700 			}
701 
702 			pChn->rowCommand = *m;
703 
704 			pChn->rightVol = pChn->newRightVol;
705 			pChn->leftVol = pChn->newLeftVol;
706 			pChn->dwFlags.reset(CHN_VIBRATO | CHN_TREMOLO);
707 			if(!m_playBehaviour[kITVibratoTremoloPanbrello]) pChn->nPanbrelloOffset = 0;
708 			pChn->nCommand = CMD_NONE;
709 			pChn->m_plugParamValueStep = 0;
710 		}
711 
712 		// Now that we know which pattern we're on, we can update time signatures (global or pattern-specific)
713 		UpdateTimeSignature();
714 
715 		if(ignoreRow)
716 		{
717 			m_PlayState.m_nTickCount = m_PlayState.m_nMusicSpeed;
718 			continue;
719 		}
720 		break;
721 	}
722 	// Should we process tick0 effects?
723 	if (!m_PlayState.m_nMusicSpeed) m_PlayState.m_nMusicSpeed = 1;
724 
725 	//End of row? stop pattern step (aka "play row").
726 #ifdef MODPLUG_TRACKER
727 	if (m_PlayState.m_nTickCount >= m_PlayState.TicksOnRow() - 1)
728 	{
729 		if(m_SongFlags[SONG_STEP])
730 		{
731 			m_SongFlags.reset(SONG_STEP);
732 			m_SongFlags.set(SONG_PAUSED);
733 		}
734 	}
735 #endif // MODPLUG_TRACKER
736 
737 	if (m_PlayState.m_nTickCount)
738 	{
739 		m_SongFlags.reset(SONG_FIRSTTICK);
740 		if(!(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))
741 		   && (GetType() != MOD_TYPE_MOD || m_SongFlags[SONG_PT_MODE])  // Fix infinite loop in "GamerMan " by MrGamer, which was made with FT2
742 		   && m_PlayState.m_nTickCount < m_PlayState.TicksOnRow())
743 		{
744 			// Emulate first tick behaviour if Row Delay is set.
745 			// Test cases: PatternDelaysRetrig.it, PatternDelaysRetrig.s3m, PatternDelaysRetrig.xm, PatternDelaysRetrig.mod
746 			if(!(m_PlayState.m_nTickCount % (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay)))
747 			{
748 				m_SongFlags.set(SONG_FIRSTTICK);
749 			}
750 		}
751 	} else
752 	{
753 		m_SongFlags.set(SONG_FIRSTTICK);
754 		m_SongFlags.reset(SONG_BREAKTOROW);
755 	}
756 
757 	// Update Effects
758 	return ProcessEffects();
759 }
760 
761 
NextRow(PlayState & playState,const bool breakRow) const762 std::pair<bool, bool> CSoundFile::NextRow(PlayState &playState, const bool breakRow) const
763 {
764 	// When having an EEx effect on the same row as a Dxx jump, the target row is not played in ProTracker.
765 	// Test case: DelayBreak.mod (based on condom_corruption by Travolta)
766 	const bool ignoreRow = playState.m_nPatternDelay > 1 && breakRow && GetType() == MOD_TYPE_MOD;
767 
768 	// Done with the last row of the pattern or jumping somewhere else (could also be a result of pattern loop to row 0, but that doesn't matter here)
769 	const bool patternTransition = playState.m_nNextRow == 0 || breakRow;
770 	if(patternTransition && GetType() == MOD_TYPE_S3M)
771 	{
772 		// Reset pattern loop start
773 		// Test case: LoopReset.s3m
774 		for(CHANNELINDEX i = 0; i < GetNumChannels(); i++)
775 		{
776 			playState.Chn[i].nPatternLoop = 0;
777 		}
778 	}
779 
780 	playState.m_nPatternDelay = 0;
781 	playState.m_nFrameDelay = 0;
782 	playState.m_nTickCount = 0;
783 	playState.m_nRow = playState.m_nNextRow;
784 	playState.m_nCurrentOrder = playState.m_nNextOrder;
785 
786 	return {ignoreRow, patternTransition};
787 }
788 
789 
SetupNextRow(PlayState & playState,const bool patternLoop) const790 void CSoundFile::SetupNextRow(PlayState &playState, const bool patternLoop) const
791 {
792 	playState.m_nNextRow = playState.m_nRow + 1;
793 	if(playState.m_nNextRow >= Patterns[playState.m_nPattern].GetNumRows())
794 	{
795 		if(!patternLoop)
796 			playState.m_nNextOrder = playState.m_nCurrentOrder + 1;
797 		playState.m_nNextRow = 0;
798 
799 		// FT2 idiosyncrasy: When E60 is used on a pattern row x, the following pattern also starts from row x
800 		// instead of the beginning of the pattern, unless there was a Bxx or Dxx effect.
801 		if(m_playBehaviour[kFT2LoopE60Restart])
802 		{
803 			playState.m_nNextRow = playState.m_nextPatStartRow;
804 			playState.m_nextPatStartRow = 0;
805 		}
806 	}
807 }
808 
809 
810 ////////////////////////////////////////////////////////////////////////////////////////////
811 // Channel effect processing
812 
813 
814 // Calculate delta for Vibrato / Tremolo / Panbrello effect
GetVibratoDelta(int type,int position) const815 int CSoundFile::GetVibratoDelta(int type, int position) const
816 {
817 	// IT compatibility: IT has its own, more precise tables
818 	if(m_playBehaviour[kITVibratoTremoloPanbrello])
819 	{
820 		position &= 0xFF;
821 		switch(type & 0x03)
822 		{
823 		case 0:	// Sine
824 		default:
825 			return ITSinusTable[position];
826 		case 1:	// Ramp down
827 			return 64 - (position + 1) / 2;
828 		case 2:	// Square
829 			return position < 128 ? 64 : 0;
830 		case 3:	// Random
831 			return mpt::random<int, 7>(AccessPRNG()) - 0x40;
832 		}
833 	} else if(GetType() & (MOD_TYPE_DIGI | MOD_TYPE_DBM))
834 	{
835 		// Other waveforms are not supported.
836 		static constexpr int8 DBMSinus[] =
837 		{
838 			33, 52, 69, 84, 96, 107, 116, 122,  125, 127,  125, 122, 116, 107, 96, 84,
839 			69, 52, 33, 13, -8, -31, -54, -79, -104,-128, -104, -79, -54, -31, -8, 13,
840 		};
841 		return DBMSinus[(position / 2u) & 0x1F];
842 	} else
843 	{
844 		position &= 0x3F;
845 		switch(type & 0x03)
846 		{
847 		case 0:	// Sine
848 		default:
849 			return ModSinusTable[position];
850 		case 1:	// Ramp down
851 			return (position < 32 ? 0 : 255) - position * 4;
852 		case 2:	// Square
853 			return position < 32 ? 127 : -127;
854 		case 3:	// Random
855 			return ModRandomTable[position];
856 		}
857 	}
858 }
859 
860 
ProcessVolumeSwing(ModChannel & chn,int & vol) const861 void CSoundFile::ProcessVolumeSwing(ModChannel &chn, int &vol) const
862 {
863 	if(m_playBehaviour[kITSwingBehaviour])
864 	{
865 		vol += chn.nVolSwing;
866 		Limit(vol, 0, 64);
867 	} else if(m_playBehaviour[kMPTOldSwingBehaviour])
868 	{
869 		vol += chn.nVolSwing;
870 		Limit(vol, 0, 256);
871 	} else
872 	{
873 		chn.nVolume += chn.nVolSwing;
874 		Limit(chn.nVolume, 0, 256);
875 		vol = chn.nVolume;
876 		chn.nVolSwing = 0;
877 	}
878 }
879 
880 
ProcessPanningSwing(ModChannel & chn) const881 void CSoundFile::ProcessPanningSwing(ModChannel &chn) const
882 {
883 	if(m_playBehaviour[kITSwingBehaviour] || m_playBehaviour[kMPTOldSwingBehaviour])
884 	{
885 		chn.nRealPan = chn.nPan + chn.nPanSwing;
886 		Limit(chn.nRealPan, 0, 256);
887 	} else
888 	{
889 		chn.nPan += chn.nPanSwing;
890 		Limit(chn.nPan, 0, 256);
891 		chn.nPanSwing = 0;
892 		chn.nRealPan = chn.nPan;
893 	}
894 }
895 
896 
ProcessTremolo(ModChannel & chn,int & vol) const897 void CSoundFile::ProcessTremolo(ModChannel &chn, int &vol) const
898 {
899 	if (chn.dwFlags[CHN_TREMOLO])
900 	{
901 		if(m_SongFlags.test_all(SONG_FIRSTTICK | SONG_PT_MODE))
902 		{
903 			// ProTracker doesn't apply tremolo nor advance on the first tick.
904 			// Test case: VibratoReset.mod
905 			return;
906 		}
907 
908 		// IT compatibility: Why would you not want to execute tremolo at volume 0?
909 		if(vol > 0 || m_playBehaviour[kITVibratoTremoloPanbrello])
910 		{
911 			// IT compatibility: We don't need a different attenuation here because of the different tables we're going to use
912 			const uint8 attenuation = ((GetType() & (MOD_TYPE_XM | MOD_TYPE_MOD)) || m_playBehaviour[kITVibratoTremoloPanbrello]) ? 5 : 6;
913 
914 			int delta = GetVibratoDelta(chn.nTremoloType, chn.nTremoloPos);
915 			if((chn.nTremoloType & 0x03) == 1 && m_playBehaviour[kFT2MODTremoloRampWaveform])
916 			{
917 				// FT2 compatibility: Tremolo ramp down / triangle implementation is weird and affected by vibrato position (copypaste bug)
918 				// Test case: TremoloWaveforms.xm, TremoloVibrato.xm
919 				uint8 ramp = (chn.nTremoloPos * 4u) & 0x7F;
920 				// Volume-colum vibrato gets executed first in FT2, so we may need to advance the vibrato position first
921 				uint32 vibPos = chn.nVibratoPos;
922 				if(!m_SongFlags[SONG_FIRSTTICK] && chn.dwFlags[CHN_VIBRATO])
923 					vibPos += chn.nVibratoSpeed;
924 				if((vibPos & 0x3F) >= 32)
925 					ramp ^= 0x7F;
926 				if((chn.nTremoloPos & 0x3F) >= 32)
927 					delta = -ramp;
928 				else
929 					delta = ramp;
930 			}
931 			if(GetType() != MOD_TYPE_DMF)
932 			{
933 				vol += (delta * chn.nTremoloDepth) / (1 << attenuation);
934 			} else
935 			{
936 				// Tremolo in DMF always attenuates by a percentage of the current note volume
937 				vol -= (vol * chn.nTremoloDepth * (64 - delta)) / (128 * 64);
938 			}
939 		}
940 		if(!m_SongFlags[SONG_FIRSTTICK] || ((GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS]))
941 		{
942 			// IT compatibility: IT has its own, more precise tables
943 			if(m_playBehaviour[kITVibratoTremoloPanbrello])
944 				chn.nTremoloPos += 4 * chn.nTremoloSpeed;
945 			else
946 				chn.nTremoloPos += chn.nTremoloSpeed;
947 		}
948 	}
949 }
950 
951 
ProcessTremor(CHANNELINDEX nChn,int & vol)952 void CSoundFile::ProcessTremor(CHANNELINDEX nChn, int &vol)
953 {
954 	ModChannel &chn = m_PlayState.Chn[nChn];
955 
956 	if(m_playBehaviour[kFT2Tremor])
957 	{
958 		// FT2 Compatibility: Weird XM tremor.
959 		// Test case: Tremor.xm
960 		if(chn.nTremorCount & 0x80)
961 		{
962 			if(!m_SongFlags[SONG_FIRSTTICK] && chn.nCommand == CMD_TREMOR)
963 			{
964 				chn.nTremorCount &= ~0x20;
965 				if(chn.nTremorCount == 0x80)
966 				{
967 					// Reached end of off-time
968 					chn.nTremorCount = (chn.nTremorParam >> 4) | 0xC0;
969 				} else if(chn.nTremorCount == 0xC0)
970 				{
971 					// Reached end of on-time
972 					chn.nTremorCount = (chn.nTremorParam & 0x0F) | 0x80;
973 				} else
974 				{
975 					chn.nTremorCount--;
976 				}
977 
978 				chn.dwFlags.set(CHN_FASTVOLRAMP);
979 			}
980 
981 			if((chn.nTremorCount & 0xE0) == 0x80)
982 			{
983 				vol = 0;
984 			}
985 		}
986 	} else if(chn.nCommand == CMD_TREMOR)
987 	{
988 		// IT compatibility 12. / 13.: Tremor
989 		if(m_playBehaviour[kITTremor])
990 		{
991 			if((chn.nTremorCount & 0x80) && chn.nLength)
992 			{
993 				if (chn.nTremorCount == 0x80)
994 					chn.nTremorCount = (chn.nTremorParam >> 4) | 0xC0;
995 				else if (chn.nTremorCount == 0xC0)
996 					chn.nTremorCount = (chn.nTremorParam & 0x0F) | 0x80;
997 				else
998 					chn.nTremorCount--;
999 			}
1000 
1001 			if((chn.nTremorCount & 0xC0) == 0x80)
1002 				vol = 0;
1003 		} else
1004 		{
1005 			uint8 ontime = chn.nTremorParam >> 4;
1006 			uint8 n = ontime + (chn.nTremorParam & 0x0F);	// Total tremor cycle time (On + Off)
1007 			if ((!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) || m_SongFlags[SONG_ITOLDEFFECTS])
1008 			{
1009 				n += 2;
1010 				ontime++;
1011 			}
1012 			uint8 tremcount = chn.nTremorCount;
1013 			if(!(GetType() & MOD_TYPE_XM))
1014 			{
1015 				if (tremcount >= n) tremcount = 0;
1016 				if (tremcount >= ontime) vol = 0;
1017 				chn.nTremorCount = tremcount + 1;
1018 			} else
1019 			{
1020 				if(m_SongFlags[SONG_FIRSTTICK])
1021 				{
1022 					// tremcount is only 0 on the first tremor tick after triggering a note.
1023 					if(tremcount > 0)
1024 					{
1025 						tremcount--;
1026 					}
1027 				} else
1028 				{
1029 					chn.nTremorCount = tremcount + 1;
1030 				}
1031 				if (tremcount % n >= ontime) vol = 0;
1032 			}
1033 		}
1034 		chn.dwFlags.set(CHN_FASTVOLRAMP);
1035 	}
1036 
1037 #ifndef NO_PLUGINS
1038 	// Plugin tremor
1039 	if(chn.nCommand == CMD_TREMOR && chn.pModInstrument && chn.pModInstrument->nMixPlug
1040 		&& !chn.pModInstrument->dwFlags[INS_MUTE]
1041 		&& !chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE]
1042 		&& ModCommand::IsNote(chn.nLastNote))
1043 	{
1044 		const ModInstrument *pIns = chn.pModInstrument;
1045 		IMixPlugin *pPlugin =  m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin;
1046 		if(pPlugin)
1047 		{
1048 			const bool isPlaying = pPlugin->IsNotePlaying(chn.nLastNote, nChn);
1049 			if(vol == 0 && isPlaying)
1050 				pPlugin->MidiCommand(*pIns, chn.nLastNote + NOTE_MAX_SPECIAL, 0, nChn);
1051 			else if(vol != 0 && !isPlaying)
1052 				pPlugin->MidiCommand(*pIns, chn.nLastNote, static_cast<uint16>(chn.nVolume), nChn);
1053 		}
1054 	}
1055 #endif // NO_PLUGINS
1056 }
1057 
1058 
IsEnvelopeProcessed(const ModChannel & chn,EnvelopeType env) const1059 bool CSoundFile::IsEnvelopeProcessed(const ModChannel &chn, EnvelopeType env) const
1060 {
1061 	if(chn.pModInstrument == nullptr)
1062 	{
1063 		return false;
1064 	}
1065 	const InstrumentEnvelope &insEnv = chn.pModInstrument->GetEnvelope(env);
1066 
1067 	// IT Compatibility: S77/S79/S7B do not disable the envelope, they just pause the counter
1068 	// Test cases: s77.it, EnvLoops.xm, PanSustainRelease.xm
1069 	bool playIfPaused = m_playBehaviour[kITEnvelopePositionHandling] || m_playBehaviour[kFT2PanSustainRelease];
1070 	return ((chn.GetEnvelope(env).flags[ENV_ENABLED] || (insEnv.dwFlags[ENV_ENABLED] && playIfPaused))
1071 		&& !insEnv.empty());
1072 }
1073 
1074 
ProcessVolumeEnvelope(ModChannel & chn,int & vol) const1075 void CSoundFile::ProcessVolumeEnvelope(ModChannel &chn, int &vol) const
1076 {
1077 	if(IsEnvelopeProcessed(chn, ENV_VOLUME))
1078 	{
1079 		const ModInstrument *pIns = chn.pModInstrument;
1080 
1081 		if(m_playBehaviour[kITEnvelopePositionHandling] && chn.VolEnv.nEnvPosition == 0)
1082 		{
1083 			// If the envelope is disabled at the very same moment as it is triggered, we do not process anything.
1084 			return;
1085 		}
1086 		const int envpos = chn.VolEnv.nEnvPosition - (m_playBehaviour[kITEnvelopePositionHandling] ? 1 : 0);
1087 		// Get values in [0, 256]
1088 		int envval = pIns->VolEnv.GetValueFromPosition(envpos, 256);
1089 
1090 		// if we are in the release portion of the envelope,
1091 		// rescale envelope factor so that it is proportional to the release point
1092 		// and release envelope beginning.
1093 		if(pIns->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET
1094 			&& chn.VolEnv.nEnvValueAtReleaseJump != NOT_YET_RELEASED)
1095 		{
1096 			int envValueAtReleaseJump = chn.VolEnv.nEnvValueAtReleaseJump;
1097 			int envValueAtReleaseNode = pIns->VolEnv[pIns->VolEnv.nReleaseNode].value * 4;
1098 
1099 			//If we have just hit the release node, force the current env value
1100 			//to be that of the release node. This works around the case where
1101 			// we have another node at the same position as the release node.
1102 			if(envpos == pIns->VolEnv[pIns->VolEnv.nReleaseNode].tick)
1103 				envval = envValueAtReleaseNode;
1104 
1105 			if(m_playBehaviour[kLegacyReleaseNode])
1106 			{
1107 				// Old, hard to grasp release node behaviour (additive)
1108 				int relativeVolumeChange = (envval - envValueAtReleaseNode) * 2;
1109 				envval = envValueAtReleaseJump + relativeVolumeChange;
1110 			} else
1111 			{
1112 				// New behaviour, truly relative to release node
1113 				if(envValueAtReleaseNode > 0)
1114 					envval = envValueAtReleaseJump * envval / envValueAtReleaseNode;
1115 				else
1116 					envval = 0;
1117 			}
1118 		}
1119 		vol = (vol * Clamp(envval, 0, 512)) / 256;
1120 	}
1121 
1122 }
1123 
1124 
ProcessPanningEnvelope(ModChannel & chn) const1125 void CSoundFile::ProcessPanningEnvelope(ModChannel &chn) const
1126 {
1127 	if(IsEnvelopeProcessed(chn, ENV_PANNING))
1128 	{
1129 		const ModInstrument *pIns = chn.pModInstrument;
1130 
1131 		if(m_playBehaviour[kITEnvelopePositionHandling] && chn.PanEnv.nEnvPosition == 0)
1132 		{
1133 			// If the envelope is disabled at the very same moment as it is triggered, we do not process anything.
1134 			return;
1135 		}
1136 
1137 		const int envpos = chn.PanEnv.nEnvPosition - (m_playBehaviour[kITEnvelopePositionHandling] ? 1 : 0);
1138 		// Get values in [-32, 32]
1139 		const int envval = pIns->PanEnv.GetValueFromPosition(envpos, 64) - 32;
1140 
1141 		int pan = chn.nRealPan;
1142 		if(pan >= 128)
1143 		{
1144 			pan += (envval * (256 - pan)) / 32;
1145 		} else
1146 		{
1147 			pan += (envval * (pan)) / 32;
1148 		}
1149 		chn.nRealPan = Clamp(pan, 0, 256);
1150 
1151 	}
1152 }
1153 
1154 
ProcessPitchFilterEnvelope(ModChannel & chn,int32 & period) const1155 int CSoundFile::ProcessPitchFilterEnvelope(ModChannel &chn, int32 &period) const
1156 {
1157 	if(IsEnvelopeProcessed(chn, ENV_PITCH))
1158 	{
1159 		const ModInstrument *pIns = chn.pModInstrument;
1160 
1161 		if(m_playBehaviour[kITEnvelopePositionHandling] && chn.PitchEnv.nEnvPosition == 0)
1162 		{
1163 			// If the envelope is disabled at the very same moment as it is triggered, we do not process anything.
1164 			return -1;
1165 		}
1166 
1167 		const int envpos = chn.PitchEnv.nEnvPosition - (m_playBehaviour[kITEnvelopePositionHandling] ? 1 : 0);
1168 		// Get values in [-256, 256]
1169 #ifdef MODPLUG_TRACKER
1170 		const int32 range = ENVELOPE_MAX;
1171 		const int32 amp = 512;
1172 #else
1173 		// TODO: AMS2 envelopes behave differently when linear slides are off - emulate with 15 * (-128...127) >> 6
1174 		// Copy over vibrato behaviour for that?
1175 		const int32 range = GetType() == MOD_TYPE_AMS ? uint8_max : ENVELOPE_MAX;
1176 		int32 amp;
1177 		switch(GetType())
1178 		{
1179 		case MOD_TYPE_AMS: amp = 64; break;
1180 		case MOD_TYPE_MDL: amp = 192; break;
1181 		default: amp = 512;
1182 		}
1183 #endif
1184 		const int envval = pIns->PitchEnv.GetValueFromPosition(envpos, amp, range) - amp / 2;
1185 
1186 		if(chn.PitchEnv.flags[ENV_FILTER])
1187 		{
1188 			// Filter Envelope: controls cutoff frequency
1189 			return SetupChannelFilter(chn, !chn.dwFlags[CHN_FILTER], envval);
1190 		} else
1191 		{
1192 			// Pitch Envelope
1193 			if(chn.HasCustomTuning())
1194 			{
1195 				if(chn.nFineTune != envval)
1196 				{
1197 					chn.nFineTune = mpt::saturate_cast<int16>(envval);
1198 					chn.m_CalculateFreq = true;
1199 					//Preliminary tests indicated that this behavior
1200 					//is very close to original(with 12TET) when finestep count
1201 					//is 15.
1202 				}
1203 			} else //Original behavior
1204 			{
1205 				const bool useFreq = PeriodsAreFrequencies();
1206 				const uint32 (&upTable)[256] = useFreq ? LinearSlideUpTable : LinearSlideDownTable;
1207 				const uint32 (&downTable)[256] = useFreq ? LinearSlideDownTable : LinearSlideUpTable;
1208 
1209 				int l = envval;
1210 				if(l < 0)
1211 				{
1212 					l = -l;
1213 					LimitMax(l, 255);
1214 					period = Util::muldiv(period, downTable[l], 65536);
1215 				} else
1216 				{
1217 					LimitMax(l, 255);
1218 					period = Util::muldiv(period, upTable[l], 65536);
1219 				}
1220 			} //End: Original behavior.
1221 		}
1222 	}
1223 	return -1;
1224 }
1225 
1226 
IncrementEnvelopePosition(ModChannel & chn,EnvelopeType envType) const1227 void CSoundFile::IncrementEnvelopePosition(ModChannel &chn, EnvelopeType envType) const
1228 {
1229 	ModChannel::EnvInfo &chnEnv = chn.GetEnvelope(envType);
1230 
1231 	if(chn.pModInstrument == nullptr || !chnEnv.flags[ENV_ENABLED])
1232 	{
1233 		return;
1234 	}
1235 
1236 	// Increase position
1237 	uint32 position = chnEnv.nEnvPosition + (m_playBehaviour[kITEnvelopePositionHandling] ? 0 : 1);
1238 
1239 	const InstrumentEnvelope &insEnv = chn.pModInstrument->GetEnvelope(envType);
1240 	if(insEnv.empty())
1241 	{
1242 		return;
1243 	}
1244 
1245 	bool endReached = false;
1246 
1247 	if(!m_playBehaviour[kITEnvelopePositionHandling])
1248 	{
1249 		// FT2-style envelope processing.
1250 		if(insEnv.dwFlags[ENV_LOOP])
1251 		{
1252 			// Normal loop active
1253 			uint32 end = insEnv[insEnv.nLoopEnd].tick;
1254 			if(!(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) end++;
1255 
1256 			// FT2 compatibility: If the sustain point is at the loop end and the sustain loop has been released, don't loop anymore.
1257 			// Test case: EnvLoops.xm
1258 			const bool escapeLoop = (insEnv.nLoopEnd == insEnv.nSustainEnd && insEnv.dwFlags[ENV_SUSTAIN] && chn.dwFlags[CHN_KEYOFF] && m_playBehaviour[kFT2EnvelopeEscape]);
1259 
1260 			if(position == end && !escapeLoop)
1261 			{
1262 				position = insEnv[insEnv.nLoopStart].tick;
1263 			}
1264 		}
1265 
1266 		if(insEnv.dwFlags[ENV_SUSTAIN] && !chn.dwFlags[CHN_KEYOFF])
1267 		{
1268 			// Envelope sustained
1269 			if(position == insEnv[insEnv.nSustainEnd].tick + 1u)
1270 			{
1271 				position = insEnv[insEnv.nSustainStart].tick;
1272 				// FT2 compatibility: If the panning envelope reaches its sustain point before key-off, it stays there forever.
1273 				// Test case: PanSustainRelease.xm
1274 				if(m_playBehaviour[kFT2PanSustainRelease] && envType == ENV_PANNING && !chn.dwFlags[CHN_KEYOFF])
1275 				{
1276 					chnEnv.flags.reset(ENV_ENABLED);
1277 				}
1278 			}
1279 		} else
1280 		{
1281 			// Limit to last envelope point
1282 			if(position > insEnv.back().tick)
1283 			{
1284 				// Env of envelope
1285 				position = insEnv.back().tick;
1286 				endReached = true;
1287 			}
1288 		}
1289 	} else
1290 	{
1291 		// IT envelope processing.
1292 		// Test case: EnvLoops.it
1293 		uint32 start, end;
1294 
1295 		// IT compatiblity: OpenMPT processes the key-off flag earlier than IT. Grab the flag from the previous tick instead.
1296 		// Test case: EnvOffLength.it
1297 		if(insEnv.dwFlags[ENV_SUSTAIN] && !chn.dwOldFlags[CHN_KEYOFF] && (chnEnv.nEnvValueAtReleaseJump == NOT_YET_RELEASED || m_playBehaviour[kReleaseNodePastSustainBug]))
1298 		{
1299 			// Envelope sustained
1300 			start = insEnv[insEnv.nSustainStart].tick;
1301 			end = insEnv[insEnv.nSustainEnd].tick + 1;
1302 		} else if(insEnv.dwFlags[ENV_LOOP])
1303 		{
1304 			// Normal loop active
1305 			start = insEnv[insEnv.nLoopStart].tick;
1306 			end = insEnv[insEnv.nLoopEnd].tick + 1;
1307 		} else
1308 		{
1309 			// Limit to last envelope point
1310 			start = end = insEnv.back().tick;
1311 			if(position > end)
1312 			{
1313 				// Env of envelope
1314 				endReached = true;
1315 			}
1316 		}
1317 
1318 		if(position >= end)
1319 		{
1320 			position = start;
1321 		}
1322 	}
1323 
1324 	if(envType == ENV_VOLUME && endReached)
1325 	{
1326 		// Special handling for volume envelopes at end of envelope
1327 		if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) || (chn.dwFlags[CHN_KEYOFF] && GetType() != MOD_TYPE_MDL))
1328 		{
1329 			chn.dwFlags.set(CHN_NOTEFADE);
1330 		}
1331 
1332 		if(insEnv.back().value == 0 && (chn.nMasterChn > 0 || (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))))
1333 		{
1334 			// Stop channel if the last envelope node is silent anyway.
1335 			chn.dwFlags.set(CHN_NOTEFADE);
1336 			chn.nFadeOutVol = 0;
1337 			chn.nRealVolume = 0;
1338 			chn.nCalcVolume = 0;
1339 		}
1340 	}
1341 
1342 	chnEnv.nEnvPosition = position + (m_playBehaviour[kITEnvelopePositionHandling] ? 1 : 0);
1343 
1344 }
1345 
1346 
IncrementEnvelopePositions(ModChannel & chn) const1347 void CSoundFile::IncrementEnvelopePositions(ModChannel &chn) const
1348 {
1349 	if (chn.isFirstTick && GetType() == MOD_TYPE_MED)
1350 		return;
1351 	IncrementEnvelopePosition(chn, ENV_VOLUME);
1352 	IncrementEnvelopePosition(chn, ENV_PANNING);
1353 	IncrementEnvelopePosition(chn, ENV_PITCH);
1354 }
1355 
1356 
ProcessInstrumentFade(ModChannel & chn,int & vol) const1357 void CSoundFile::ProcessInstrumentFade(ModChannel &chn, int &vol) const
1358 {
1359 	// FadeOut volume
1360 	if(chn.dwFlags[CHN_NOTEFADE] && chn.pModInstrument != nullptr)
1361 	{
1362 		const ModInstrument *pIns = chn.pModInstrument;
1363 
1364 		uint32 fadeout = pIns->nFadeOut;
1365 		if (fadeout)
1366 		{
1367 			chn.nFadeOutVol -= fadeout * 2;
1368 			if (chn.nFadeOutVol <= 0) chn.nFadeOutVol = 0;
1369 			vol = (vol * chn.nFadeOutVol) / 65536;
1370 		} else if (!chn.nFadeOutVol)
1371 		{
1372 			vol = 0;
1373 		}
1374 	}
1375 }
1376 
1377 
ProcessPitchPanSeparation(int32 & pan,int note,const ModInstrument & instr)1378 void CSoundFile::ProcessPitchPanSeparation(int32 &pan, int note, const ModInstrument &instr)
1379 {
1380 	if(!instr.nPPS || note == NOTE_NONE)
1381 		return;
1382 	// with PPS = 16 / PPC = C-5, E-6 will pan hard right (and D#6 will not)
1383 	int32 delta = (note - instr.nPPC - NOTE_MIN) * instr.nPPS / 2;
1384 	pan = Clamp(pan + delta, 0, 256);
1385 }
1386 
1387 
ProcessPanbrello(ModChannel & chn) const1388 void CSoundFile::ProcessPanbrello(ModChannel &chn) const
1389 {
1390 	int pdelta = chn.nPanbrelloOffset;
1391 	if(chn.rowCommand.command == CMD_PANBRELLO)
1392 	{
1393 		uint32 panpos;
1394 		// IT compatibility: IT has its own, more precise tables
1395 		if(m_playBehaviour[kITVibratoTremoloPanbrello])
1396 			panpos = chn.nPanbrelloPos;
1397 		else
1398 			panpos = ((chn.nPanbrelloPos + 0x10) >> 2);
1399 
1400 		pdelta = GetVibratoDelta(chn.nPanbrelloType, panpos);
1401 
1402 		// IT compatibility: Sample-and-hold style random panbrello (tremolo and vibrato don't use this mechanism in IT)
1403 		// Test case: RandomWaveform.it
1404 		if(m_playBehaviour[kITSampleAndHoldPanbrello] && chn.nPanbrelloType == 3)
1405 		{
1406 			if(chn.nPanbrelloPos == 0 || chn.nPanbrelloPos >= chn.nPanbrelloSpeed)
1407 			{
1408 				chn.nPanbrelloPos = 0;
1409 				chn.nPanbrelloRandomMemory = static_cast<int8>(pdelta);
1410 			}
1411 			chn.nPanbrelloPos++;
1412 			pdelta = chn.nPanbrelloRandomMemory;
1413 		} else
1414 		{
1415 			chn.nPanbrelloPos += chn.nPanbrelloSpeed;
1416 		}
1417 		// IT compatibility: Panbrello effect is active until next note or panning command.
1418 		// Test case: PanbrelloHold.it
1419 		if(m_playBehaviour[kITPanbrelloHold])
1420 		{
1421 			chn.nPanbrelloOffset = static_cast<int8>(pdelta);
1422 		}
1423 	}
1424 	if(pdelta)
1425 	{
1426 		pdelta = ((pdelta * (int)chn.nPanbrelloDepth) + 2) / 8;
1427 		pdelta += chn.nRealPan;
1428 		chn.nRealPan = Clamp(pdelta, 0, 256);
1429 	}
1430 }
1431 
1432 
ProcessArpeggio(CHANNELINDEX nChn,int32 & period,Tuning::NOTEINDEXTYPE & arpeggioSteps)1433 void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int32 &period, Tuning::NOTEINDEXTYPE &arpeggioSteps)
1434 {
1435 	ModChannel &chn = m_PlayState.Chn[nChn];
1436 
1437 #ifndef NO_PLUGINS
1438 	// Plugin arpeggio
1439 	if(chn.pModInstrument && chn.pModInstrument->nMixPlug
1440 		&& !chn.pModInstrument->dwFlags[INS_MUTE]
1441 		&& !chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE])
1442 	{
1443 		const ModInstrument *pIns = chn.pModInstrument;
1444 		IMixPlugin *pPlugin =  m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin;
1445 		if(pPlugin)
1446 		{
1447 			uint8 step = 0;
1448 			const bool arpOnRow = (chn.rowCommand.command == CMD_ARPEGGIO);
1449 			const ModCommand::NOTE lastNote = ModCommand::IsNote(chn.nLastNote) ? static_cast<ModCommand::NOTE>(pIns->NoteMap[chn.nLastNote - NOTE_MIN]) : static_cast<ModCommand::NOTE>(NOTE_NONE);
1450 			if(arpOnRow)
1451 			{
1452 				switch(m_PlayState.m_nTickCount % 3)
1453 				{
1454 				case 1: step = chn.nArpeggio >> 4; break;
1455 				case 2: step = chn.nArpeggio & 0x0F; break;
1456 				}
1457 				chn.nArpeggioBaseNote = lastNote;
1458 			}
1459 
1460 			// Trigger new note:
1461 			// - If there's an arpeggio on this row and
1462 			//   - the note to trigger is not the same as the previous arpeggio note or
1463 			//   - a pattern note has just been triggered on this tick
1464 			// - If there's no arpeggio
1465 			//   - but an arpeggio note is still active and
1466 			//   - there's no note stop or new note that would stop it anyway
1467 			if((arpOnRow && chn.nArpeggioLastNote != chn.nArpeggioBaseNote + step && (!m_SongFlags[SONG_FIRSTTICK] || !chn.rowCommand.IsNote()))
1468 				|| (!arpOnRow && chn.rowCommand.note == NOTE_NONE && chn.nArpeggioLastNote != NOTE_NONE))
1469 				SendMIDINote(nChn, chn.nArpeggioBaseNote + step, static_cast<uint16>(chn.nVolume));
1470 			// Stop note:
1471 			// - If some arpeggio note is still registered or
1472 			// - When starting an arpeggio on a row with no other note on it, stop some possibly still playing note.
1473 			if(chn.nArpeggioLastNote != NOTE_NONE)
1474 				SendMIDINote(nChn, chn.nArpeggioLastNote + NOTE_MAX_SPECIAL, 0);
1475 			else if(arpOnRow && m_SongFlags[SONG_FIRSTTICK] && !chn.rowCommand.IsNote() && ModCommand::IsNote(lastNote))
1476 				SendMIDINote(nChn, lastNote + NOTE_MAX_SPECIAL, 0);
1477 
1478 			if(chn.rowCommand.command == CMD_ARPEGGIO)
1479 				chn.nArpeggioLastNote = chn.nArpeggioBaseNote + step;
1480 			else
1481 				chn.nArpeggioLastNote = NOTE_NONE;
1482 		}
1483 	}
1484 #endif // NO_PLUGINS
1485 
1486 	if(chn.nCommand == CMD_ARPEGGIO)
1487 	{
1488 		if(chn.HasCustomTuning())
1489 		{
1490 			switch(m_PlayState.m_nTickCount % 3)
1491 			{
1492 			case 0: arpeggioSteps = 0; break;
1493 			case 1: arpeggioSteps = chn.nArpeggio >> 4; break;
1494 			case 2: arpeggioSteps = chn.nArpeggio & 0x0F; break;
1495 			}
1496 			chn.m_CalculateFreq = true;
1497 			chn.m_ReCalculateFreqOnFirstTick = true;
1498 		} else
1499 		{
1500 			if(GetType() == MOD_TYPE_MT2 && m_SongFlags[SONG_FIRSTTICK])
1501 			{
1502 				// MT2 resets any previous portamento when an arpeggio occurs.
1503 				chn.nPeriod = period = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed);
1504 			}
1505 
1506 			if(m_playBehaviour[kITArpeggio])
1507 			{
1508 				//IT playback compatibility 01 & 02
1509 
1510 				// Pattern delay restarts tick counting. Not quite correct yet!
1511 				const uint32 tick = m_PlayState.m_nTickCount % (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay);
1512 				if(chn.nArpeggio != 0)
1513 				{
1514 					uint32 arpRatio = 65536;
1515 					switch(tick % 3)
1516 					{
1517 					case 1: arpRatio = LinearSlideUpTable[(chn.nArpeggio >> 4) * 16]; break;
1518 					case 2: arpRatio = LinearSlideUpTable[(chn.nArpeggio & 0x0F) * 16]; break;
1519 					}
1520 					if(PeriodsAreFrequencies())
1521 						period = Util::muldivr(period, arpRatio, 65536);
1522 					else
1523 						period = Util::muldivr(period, 65536, arpRatio);
1524 				}
1525 			} else if(m_playBehaviour[kFT2Arpeggio])
1526 			{
1527 				// FastTracker 2: Swedish tracker logic (TM) arpeggio
1528 				if(!m_SongFlags[SONG_FIRSTTICK])
1529 				{
1530 					// Arpeggio is added on top of current note, but cannot do it the IT way because of
1531 					// the behaviour in ArpeggioClamp.xm.
1532 					// Test case: ArpSlide.xm
1533 					uint32 note = 0;
1534 
1535 					// The fact that arpeggio behaves in a totally fucked up way at 16 ticks/row or more is that the arpeggio offset LUT only has 16 entries in FT2.
1536 					// At more than 16 ticks/row, FT2 reads into the vibrato table, which is placed right after the arpeggio table.
1537 					// Test case: Arpeggio.xm
1538 					int arpPos = m_PlayState.m_nMusicSpeed - (m_PlayState.m_nTickCount % m_PlayState.m_nMusicSpeed);
1539 					if(arpPos > 16)
1540 						arpPos = 2;
1541 					else if(arpPos == 16)
1542 						arpPos = 0;
1543 					else
1544 						arpPos %= 3;
1545 					switch(arpPos)
1546 					{
1547 					case 1: note = (chn.nArpeggio >> 4); break;
1548 					case 2: note = (chn.nArpeggio & 0x0F); break;
1549 					}
1550 
1551 					if(arpPos != 0)
1552 					{
1553 						// Arpeggio is added on top of current note, but cannot do it the IT way because of
1554 						// the behaviour in ArpeggioClamp.xm.
1555 						// Test case: ArpSlide.xm
1556 						note += GetNoteFromPeriod(period, chn.nFineTune, chn.nC5Speed);
1557 
1558 						period = GetPeriodFromNote(note, chn.nFineTune, chn.nC5Speed);
1559 
1560 						// FT2 compatibility: FT2 has a different note limit for Arpeggio.
1561 						// Test case: ArpeggioClamp.xm
1562 						if(note >= 108 + NOTE_MIN)
1563 						{
1564 							period = std::max(static_cast<uint32>(period), GetPeriodFromNote(108 + NOTE_MIN, 0, chn.nC5Speed));
1565 						}
1566 					}
1567 				}
1568 			}
1569 			// Other trackers
1570 			else
1571 			{
1572 				uint32 tick = m_PlayState.m_nTickCount;
1573 
1574 				// TODO other likely formats for MOD case: MED, OKT, etc
1575 				uint8 note = (GetType() != MOD_TYPE_MOD) ? chn.nNote : static_cast<uint8>(GetNoteFromPeriod(period, chn.nFineTune, chn.nC5Speed));
1576 				if(GetType() & (MOD_TYPE_DBM | MOD_TYPE_DIGI))
1577 					tick += 2;
1578 				switch(tick % 3)
1579 				{
1580 				case 1: note += (chn.nArpeggio >> 4); break;
1581 				case 2: note += (chn.nArpeggio & 0x0F); break;
1582 				}
1583 				if(note != chn.nNote || (GetType() & (MOD_TYPE_DBM | MOD_TYPE_DIGI | MOD_TYPE_STM)) || m_playBehaviour[KST3PortaAfterArpeggio])
1584 				{
1585 					if(m_SongFlags[SONG_PT_MODE])
1586 					{
1587 						// Weird arpeggio wrap-around in ProTracker.
1588 						// Test case: ArpWraparound.mod, and the snare sound in "Jim is dead" by doh.
1589 						if(note == NOTE_MIDDLEC + 24)
1590 						{
1591 							period = int32_max;
1592 							return;
1593 						} else if(note > NOTE_MIDDLEC + 24)
1594 						{
1595 							note -= 37;
1596 						}
1597 					}
1598 					period = GetPeriodFromNote(note, chn.nFineTune, chn.nC5Speed);
1599 
1600 					if(GetType() & (MOD_TYPE_DBM | MOD_TYPE_DIGI | MOD_TYPE_PSM | MOD_TYPE_STM | MOD_TYPE_OKT))
1601 					{
1602 						// The arpeggio note offset remains effective after the end of the current row in ScreamTracker 2.
1603 						// This fixes the flute lead in MORPH.STM by Skaven, pattern 27.
1604 						// Note that ScreamTracker 2.24 handles arpeggio slightly differently: It only considers the lower
1605 						// nibble, and switches to that note halfway through the row.
1606 						chn.nPeriod = period;
1607 					} else if(m_playBehaviour[KST3PortaAfterArpeggio])
1608 					{
1609 						chn.nArpeggioLastNote = note;
1610 					}
1611 				}
1612 			}
1613 		}
1614 	}
1615 }
1616 
1617 
ProcessVibrato(CHANNELINDEX nChn,int32 & period,Tuning::RATIOTYPE & vibratoFactor)1618 void CSoundFile::ProcessVibrato(CHANNELINDEX nChn, int32 &period, Tuning::RATIOTYPE &vibratoFactor)
1619 {
1620 	ModChannel &chn = m_PlayState.Chn[nChn];
1621 
1622 	if(chn.dwFlags[CHN_VIBRATO])
1623 	{
1624 		const bool advancePosition = !m_SongFlags[SONG_FIRSTTICK] || ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !(m_SongFlags[SONG_ITOLDEFFECTS]));
1625 
1626 		if(GetType() == MOD_TYPE_669)
1627 		{
1628 			if(chn.nVibratoPos % 2u)
1629 			{
1630 				period += chn.nVibratoDepth * 167;	// Already multiplied by 4, and it seems like the real factor here is 669... how original =)
1631 			}
1632 			chn.nVibratoPos++;
1633 			return;
1634 		}
1635 
1636 		// IT compatibility: IT has its own, more precise tables and pre-increments the vibrato position
1637 		if(advancePosition && m_playBehaviour[kITVibratoTremoloPanbrello])
1638 			chn.nVibratoPos += 4 * chn.nVibratoSpeed;
1639 
1640 		int vdelta = GetVibratoDelta(chn.nVibratoType, chn.nVibratoPos);
1641 
1642 		if(chn.HasCustomTuning())
1643 		{
1644 			//Hack implementation: Scaling vibratofactor to [0.95; 1.05]
1645 			//using figure from above tables and vibratodepth parameter
1646 			vibratoFactor += 0.05f * (vdelta * chn.nVibratoDepth) / (128.0f * 60.0f);
1647 			chn.m_CalculateFreq = true;
1648 			chn.m_ReCalculateFreqOnFirstTick = false;
1649 
1650 			if(m_PlayState.m_nTickCount + 1 == m_PlayState.m_nMusicSpeed)
1651 				chn.m_ReCalculateFreqOnFirstTick = true;
1652 		} else
1653 		{
1654 			// Original behaviour
1655 			if(m_SongFlags.test_all(SONG_FIRSTTICK | SONG_PT_MODE) || ((GetType() & (MOD_TYPE_DIGI | MOD_TYPE_DBM)) && m_SongFlags[SONG_FIRSTTICK]))
1656 			{
1657 				// ProTracker doesn't apply vibrato nor advance on the first tick.
1658 				// Test case: VibratoReset.mod
1659 				return;
1660 			} else if((GetType() & (MOD_TYPE_XM | MOD_TYPE_MOD)) && (chn.nVibratoType & 0x03) == 1)
1661 			{
1662 				// FT2 compatibility: Vibrato ramp down table is upside down.
1663 				// Test case: VibratoWaveforms.xm
1664 				vdelta = -vdelta;
1665 			}
1666 
1667 			uint32 vdepth;
1668 			// IT compatibility: correct vibrato depth
1669 			if(m_playBehaviour[kITVibratoTremoloPanbrello])
1670 			{
1671 				// Yes, vibrato goes backwards with old effects enabled!
1672 				if(m_SongFlags[SONG_ITOLDEFFECTS])
1673 				{
1674 					// Test case: vibrato-oldfx.it
1675 					vdepth = 5;
1676 				} else
1677 				{
1678 					// Test case: vibrato.it
1679 					vdepth = 6;
1680 					vdelta = -vdelta;
1681 				}
1682 			} else
1683 			{
1684 				if(m_SongFlags[SONG_S3MOLDVIBRATO])
1685 					vdepth = 5;
1686 				else if(GetType() == MOD_TYPE_DTM)
1687 					vdepth = 8;
1688 				else if(GetType() & (MOD_TYPE_DBM | MOD_TYPE_MTM))
1689 					vdepth = 7;
1690 				else if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS])
1691 					vdepth = 7;
1692 				else
1693 					vdepth = 6;
1694 
1695 				// ST3 compatibility: Do not distinguish between vibrato types in effect memory
1696 				// Test case: VibratoTypeChange.s3m
1697 				if(m_playBehaviour[kST3VibratoMemory] && chn.rowCommand.command == CMD_FINEVIBRATO)
1698 					vdepth += 2;
1699 			}
1700 
1701 			vdelta = (-vdelta * static_cast<int>(chn.nVibratoDepth)) / (1 << vdepth);
1702 
1703 			DoFreqSlide(chn, period, vdelta);
1704 
1705 			// Process MIDI vibrato for plugins:
1706 #ifndef NO_PLUGINS
1707 			IMixPlugin *plugin = GetChannelInstrumentPlugin(nChn);
1708 			if(plugin != nullptr)
1709 			{
1710 				// If the Pitch Wheel Depth is configured correctly (so it's the same as the plugin's PWD),
1711 				// MIDI vibrato will sound identical to vibrato with linear slides enabled.
1712 				int8 pwd = 2;
1713 				if(chn.pModInstrument != nullptr)
1714 				{
1715 					pwd = chn.pModInstrument->midiPWD;
1716 				}
1717 				plugin->MidiVibrato(vdelta, pwd, nChn);
1718 			}
1719 #endif // NO_PLUGINS
1720 		}
1721 
1722 		// Advance vibrato position - IT updates on every tick, unless "old effects" are enabled (in this case it only updates on non-first ticks like other trackers)
1723 		// IT compatibility: IT has its own, more precise tables and pre-increments the vibrato position
1724 		if(advancePosition && !m_playBehaviour[kITVibratoTremoloPanbrello])
1725 			chn.nVibratoPos += chn.nVibratoSpeed;
1726 	} else if(chn.dwOldFlags[CHN_VIBRATO])
1727 	{
1728 		// Stop MIDI vibrato for plugins:
1729 #ifndef NO_PLUGINS
1730 		IMixPlugin *plugin = GetChannelInstrumentPlugin(nChn);
1731 		if(plugin != nullptr)
1732 		{
1733 			plugin->MidiVibrato(0, 0, nChn);
1734 		}
1735 #endif // NO_PLUGINS
1736 	}
1737 }
1738 
1739 
ProcessSampleAutoVibrato(ModChannel & chn,int32 & period,Tuning::RATIOTYPE & vibratoFactor,int & nPeriodFrac) const1740 void CSoundFile::ProcessSampleAutoVibrato(ModChannel &chn, int32 &period, Tuning::RATIOTYPE &vibratoFactor, int &nPeriodFrac) const
1741 {
1742 	// Sample Auto-Vibrato
1743 	if(chn.pModSample != nullptr && chn.pModSample->nVibDepth)
1744 	{
1745 		const ModSample *pSmp = chn.pModSample;
1746 		const bool hasTuning = chn.HasCustomTuning();
1747 
1748 		// In IT compatible mode, we use always frequencies, otherwise we use periods, which are upside down.
1749 		// In this context, the "up" tables refer to the tables that increase frequency, and the down tables are the ones that decrease frequency.
1750 		const bool useFreq = PeriodsAreFrequencies();
1751 		const uint32 (&upTable)[256] = useFreq ? LinearSlideUpTable : LinearSlideDownTable;
1752 		const uint32 (&downTable)[256] = useFreq ? LinearSlideDownTable : LinearSlideUpTable;
1753 		const uint32 (&fineUpTable)[16] = useFreq ? FineLinearSlideUpTable : FineLinearSlideDownTable;
1754 		const uint32 (&fineDownTable)[16] = useFreq ? FineLinearSlideDownTable : FineLinearSlideUpTable;
1755 
1756 		// IT compatibility: Autovibrato is so much different in IT that I just put this in a separate code block, to get rid of a dozen IsCompatibilityMode() calls.
1757 		if(m_playBehaviour[kITVibratoTremoloPanbrello] && !hasTuning && GetType() != MOD_TYPE_MT2)
1758 		{
1759 			if(!pSmp->nVibRate)
1760 				return;
1761 
1762 			// Schism's autovibrato code
1763 
1764 			/*
1765 			X86 Assembler from ITTECH.TXT:
1766 			1) Mov AX, [SomeVariableNameRelatingToVibrato]
1767 			2) Add AL, Rate
1768 			3) AdC AH, 0
1769 			4) AH contains the depth of the vibrato as a fine-linear slide.
1770 			5) Mov [SomeVariableNameRelatingToVibrato], AX  ; For the next cycle.
1771 			*/
1772 			const int vibpos = chn.nAutoVibPos & 0xFF;
1773 			int adepth = chn.nAutoVibDepth; // (1)
1774 			adepth += pSmp->nVibSweep; // (2 & 3)
1775 			LimitMax(adepth, static_cast<int>(pSmp->nVibDepth * 256u));
1776 			chn.nAutoVibDepth = adepth; // (5)
1777 			adepth /= 256; // (4)
1778 
1779 			chn.nAutoVibPos += pSmp->nVibRate;
1780 
1781 			int vdelta;
1782 			switch(pSmp->nVibType)
1783 			{
1784 			case VIB_RANDOM:
1785 				vdelta = mpt::random<int, 7>(AccessPRNG()) - 0x40;
1786 				break;
1787 			case VIB_RAMP_DOWN:
1788 				vdelta = 64 - (vibpos + 1) / 2;
1789 				break;
1790 			case VIB_RAMP_UP:
1791 				vdelta = ((vibpos + 1) / 2) - 64;
1792 				break;
1793 			case VIB_SQUARE:
1794 				vdelta = vibpos < 128 ? 64 : 0;
1795 				break;
1796 			case VIB_SINE:
1797 			default:
1798 				vdelta = ITSinusTable[vibpos];
1799 				break;
1800 			}
1801 
1802 			vdelta = (vdelta * adepth) / 64;
1803 			uint32 l = std::abs(vdelta);
1804 			LimitMax(period, Util::MaxValueOfType(period) / 256);
1805 			period *= 256;
1806 			if(vdelta < 0)
1807 			{
1808 				vdelta = Util::muldiv(period, downTable[l / 4u], 0x10000) - period;
1809 				if (l & 0x03)
1810 				{
1811 					vdelta += Util::muldiv(period, fineDownTable[l & 0x03], 0x10000) - period;
1812 				}
1813 			} else
1814 			{
1815 				vdelta = Util::muldiv(period, upTable[l / 4u], 0x10000) - period;
1816 				if (l & 0x03)
1817 				{
1818 					vdelta += Util::muldiv(period, fineUpTable[l & 0x03], 0x10000) - period;
1819 				}
1820 			}
1821 			period = (period + vdelta) / 256;
1822 			nPeriodFrac = vdelta & 0xFF;
1823 		} else
1824 		{
1825 			// MPT's autovibrato code
1826 			if (pSmp->nVibSweep == 0 && !(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)))
1827 			{
1828 				chn.nAutoVibDepth = pSmp->nVibDepth * 256;
1829 			} else
1830 			{
1831 				// Calculate current autovibrato depth using vibsweep
1832 				if (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))
1833 				{
1834 					chn.nAutoVibDepth += pSmp->nVibSweep * 2u;
1835 				} else
1836 				{
1837 					if(!chn.dwFlags[CHN_KEYOFF])
1838 					{
1839 						chn.nAutoVibDepth += (pSmp->nVibDepth * 256u) / pSmp->nVibSweep;
1840 					}
1841 				}
1842 				LimitMax(chn.nAutoVibDepth, static_cast<int>(pSmp->nVibDepth * 256u));
1843 			}
1844 			chn.nAutoVibPos += pSmp->nVibRate;
1845 			int vdelta;
1846 			switch(pSmp->nVibType)
1847 			{
1848 			case VIB_RANDOM:
1849 				vdelta = ModRandomTable[chn.nAutoVibPos & 0x3F];
1850 				chn.nAutoVibPos++;
1851 				break;
1852 			case VIB_RAMP_DOWN:
1853 				vdelta = ((0x40 - (chn.nAutoVibPos / 2u)) & 0x7F) - 0x40;
1854 				break;
1855 			case VIB_RAMP_UP:
1856 				vdelta = ((0x40 + (chn.nAutoVibPos / 2u)) & 0x7F) - 0x40;
1857 				break;
1858 			case VIB_SQUARE:
1859 				vdelta = (chn.nAutoVibPos & 128) ? +64 : -64;
1860 				break;
1861 			case VIB_SINE:
1862 			default:
1863 				if(GetType() != MOD_TYPE_MT2)
1864 				{
1865 					vdelta = -ITSinusTable[chn.nAutoVibPos & 0xFF];
1866 				} else
1867 				{
1868 					// Fix flat-sounding pads in "another worlds" by Eternal Engine.
1869 					// Vibrato starts at the maximum amplitude of the sine wave
1870 					// and the vibrato frequency never decreases below the original note's frequency.
1871 					vdelta = (-ITSinusTable[(chn.nAutoVibPos + 192) & 0xFF] + 64) / 2;
1872 				}
1873 			}
1874 			int n = (vdelta * chn.nAutoVibDepth) / 256;
1875 
1876 			if(hasTuning)
1877 			{
1878 				//Vib sweep is not taken into account here.
1879 				vibratoFactor += 0.05F * pSmp->nVibDepth * vdelta / 4096.0f; //4096 == 64^2
1880 				//See vibrato for explanation.
1881 				chn.m_CalculateFreq = true;
1882 				/*
1883 				Finestep vibrato:
1884 				const float autoVibDepth = pSmp->nVibDepth * val / 4096.0f; //4096 == 64^2
1885 				vibratoFineSteps += static_cast<CTuning::FINESTEPTYPE>(chn.pModInstrument->pTuning->GetFineStepCount() *  autoVibDepth);
1886 				chn.m_CalculateFreq = true;
1887 				*/
1888 			}
1889 			else //Original behavior
1890 			{
1891 				if (GetType() != MOD_TYPE_XM)
1892 				{
1893 					int df1, df2;
1894 					if (n < 0)
1895 					{
1896 						n = -n;
1897 						uint32 n1 = n / 256;
1898 						df1 = downTable[n1];
1899 						df2 = downTable[n1+1];
1900 					} else
1901 					{
1902 						uint32 n1 = n / 256;
1903 						df1 = upTable[n1];
1904 						df2 = upTable[n1+1];
1905 					}
1906 					n /= 4;
1907 					period = Util::muldiv(period, df1 + ((df2 - df1) * (n & 0x3F) / 64), 256);
1908 					nPeriodFrac = period & 0xFF;
1909 					period /= 256;
1910 				} else
1911 				{
1912 					period += (n / 64);
1913 				}
1914 			} //Original MPT behavior
1915 		}
1916 	}
1917 }
1918 
1919 
ProcessRamping(ModChannel & chn) const1920 void CSoundFile::ProcessRamping(ModChannel &chn) const
1921 {
1922 	chn.leftRamp = chn.rightRamp = 0;
1923 	LimitMax(chn.newLeftVol, int32_max >> VOLUMERAMPPRECISION);
1924 	LimitMax(chn.newRightVol, int32_max >> VOLUMERAMPPRECISION);
1925 	if(chn.dwFlags[CHN_VOLUMERAMP] && (chn.leftVol != chn.newLeftVol || chn.rightVol != chn.newRightVol))
1926 	{
1927 		const bool rampUp = (chn.newLeftVol > chn.leftVol) || (chn.newRightVol > chn.rightVol);
1928 		int32 rampLength, globalRampLength, instrRampLength = 0;
1929 		rampLength = globalRampLength = (rampUp ? m_MixerSettings.GetVolumeRampUpSamples() : m_MixerSettings.GetVolumeRampDownSamples());
1930 		//XXXih: add real support for bidi ramping here
1931 
1932 		if(m_playBehaviour[kFT2VolumeRamping] && (GetType() & MOD_TYPE_XM))
1933 		{
1934 			// apply FT2-style super-soft volume ramping (5ms), overriding openmpt settings
1935 			rampLength = globalRampLength = Util::muldivr(5, m_MixerSettings.gdwMixingFreq, 1000);
1936 		}
1937 
1938 		if(chn.pModInstrument != nullptr && rampUp)
1939 		{
1940 			instrRampLength = chn.pModInstrument->nVolRampUp;
1941 			rampLength = instrRampLength ? (m_MixerSettings.gdwMixingFreq * instrRampLength / 100000) : globalRampLength;
1942 		}
1943 		const bool enableCustomRamp = (instrRampLength > 0);
1944 
1945 		if(!rampLength)
1946 		{
1947 			rampLength = 1;
1948 		}
1949 
1950 		int32 leftDelta = ((chn.newLeftVol - chn.leftVol) * (1 << VOLUMERAMPPRECISION));
1951 		int32 rightDelta = ((chn.newRightVol - chn.rightVol) * (1 << VOLUMERAMPPRECISION));
1952 		if(!enableCustomRamp)
1953 		{
1954 			// Extra-smooth ramping, unless we're forced to use the default values
1955 			if((chn.leftVol | chn.rightVol) && (chn.newLeftVol | chn.newRightVol) && !chn.dwFlags[CHN_FASTVOLRAMP])
1956 			{
1957 				rampLength = m_PlayState.m_nBufferCount;
1958 				Limit(rampLength, globalRampLength, int32(1 << (VOLUMERAMPPRECISION - 1)));
1959 			}
1960 		}
1961 
1962 		chn.leftRamp = leftDelta / rampLength;
1963 		chn.rightRamp = rightDelta / rampLength;
1964 		chn.leftVol = chn.newLeftVol - ((chn.leftRamp * rampLength) / (1 << VOLUMERAMPPRECISION));
1965 		chn.rightVol = chn.newRightVol - ((chn.rightRamp * rampLength) / (1 << VOLUMERAMPPRECISION));
1966 
1967 		if (chn.leftRamp|chn.rightRamp)
1968 		{
1969 			chn.nRampLength = rampLength;
1970 		} else
1971 		{
1972 			chn.dwFlags.reset(CHN_VOLUMERAMP);
1973 			chn.leftVol = chn.newLeftVol;
1974 			chn.rightVol = chn.newRightVol;
1975 		}
1976 	} else
1977 	{
1978 		chn.dwFlags.reset(CHN_VOLUMERAMP);
1979 		chn.leftVol = chn.newLeftVol;
1980 		chn.rightVol = chn.newRightVol;
1981 	}
1982 	chn.rampLeftVol = chn.leftVol * (1 << VOLUMERAMPPRECISION);
1983 	chn.rampRightVol = chn.rightVol * (1 << VOLUMERAMPPRECISION);
1984 	chn.dwFlags.reset(CHN_FASTVOLRAMP);
1985 }
1986 
1987 
1988 // Returns channel increment and frequency with FREQ_FRACBITS fractional bits
GetChannelIncrement(const ModChannel & chn,uint32 period,int periodFrac) const1989 std::pair<SamplePosition, uint32> CSoundFile::GetChannelIncrement(const ModChannel &chn, uint32 period, int periodFrac) const
1990 {
1991 	uint32 freq;
1992 	if(!chn.HasCustomTuning())
1993 		freq = GetFreqFromPeriod(period, chn.nC5Speed, periodFrac);
1994 	else
1995 		freq = chn.nPeriod;
1996 
1997 	const ModInstrument *ins = chn.pModInstrument;
1998 
1999 	if(int32 finetune = chn.microTuning; finetune != 0)
2000 	{
2001 		if(ins)
2002 			finetune *= ins->midiPWD;
2003 		if(finetune)
2004 			freq = mpt::saturate_round<uint32>(freq * std::pow(2.0, finetune / (12.0 * 256.0 * 128.0)));
2005 	}
2006 
2007 	// Applying Pitch/Tempo lock
2008 	if(ins && ins->pitchToTempoLock.GetRaw())
2009 	{
2010 		freq = Util::muldivr(freq, m_PlayState.m_nMusicTempo.GetRaw(), ins->pitchToTempoLock.GetRaw());
2011 	}
2012 
2013 	// Avoid increment to overflow and become negative with unrealisticly high frequencies.
2014 	LimitMax(freq, uint32(int32_max));
2015 	return {SamplePosition::Ratio(freq, m_MixerSettings.gdwMixingFreq << FREQ_FRACBITS), freq};
2016 }
2017 
2018 
2019 ////////////////////////////////////////////////////////////////////////////////////////////
2020 // Handles envelopes & mixer setup
2021 
ReadNote()2022 bool CSoundFile::ReadNote()
2023 {
2024 #ifdef MODPLUG_TRACKER
2025 	// Checking end of row ?
2026 	if(m_SongFlags[SONG_PAUSED])
2027 	{
2028 		m_PlayState.m_nTickCount = 0;
2029 		if (!m_PlayState.m_nMusicSpeed) m_PlayState.m_nMusicSpeed = 6;
2030 		if (!m_PlayState.m_nMusicTempo.GetRaw()) m_PlayState.m_nMusicTempo.Set(125);
2031 	} else
2032 #endif // MODPLUG_TRACKER
2033 	{
2034 		if(!ProcessRow())
2035 			return false;
2036 	}
2037 	////////////////////////////////////////////////////////////////////////////////////
2038 	if (m_PlayState.m_nMusicTempo.GetRaw() == 0) return false;
2039 
2040 	m_PlayState.m_nSamplesPerTick = GetTickDuration(m_PlayState);
2041 	m_PlayState.m_nBufferCount = m_PlayState.m_nSamplesPerTick;
2042 
2043 	// Master Volume + Pre-Amplification / Attenuation setup
2044 	uint32 nMasterVol;
2045 	{
2046 		CHANNELINDEX nchn32 = Clamp(m_nChannels, CHANNELINDEX(1), CHANNELINDEX(31));
2047 
2048 		uint32 mastervol;
2049 
2050 		if (m_PlayConfig.getUseGlobalPreAmp())
2051 		{
2052 			int realmastervol = m_MixerSettings.m_nPreAmp;
2053 			if (realmastervol > 0x80)
2054 			{
2055 				//Attenuate global pre-amp depending on num channels
2056 				realmastervol = 0x80 + ((realmastervol - 0x80) * (nchn32 + 4)) / 16;
2057 			}
2058 			mastervol = (realmastervol * (m_nSamplePreAmp)) / 64;
2059 		} else
2060 		{
2061 			//Preferred option: don't use global pre-amp at all.
2062 			mastervol = m_nSamplePreAmp;
2063 		}
2064 
2065 		if (m_PlayConfig.getUseGlobalPreAmp())
2066 		{
2067 			uint32 attenuation =
2068 #ifndef NO_AGC
2069 				(m_MixerSettings.DSPMask & SNDDSP_AGC) ? PreAmpAGCTable[nchn32 / 2u] :
2070 #endif
2071 				PreAmpTable[nchn32 / 2u];
2072 			if(attenuation < 1) attenuation = 1;
2073 			nMasterVol = (mastervol << 7) / attenuation;
2074 		} else
2075 		{
2076 			nMasterVol = mastervol;
2077 		}
2078 	}
2079 
2080 	////////////////////////////////////////////////////////////////////////////////////
2081 	// Update channels data
2082 	m_nMixChannels = 0;
2083 	for (CHANNELINDEX nChn = 0; nChn < MAX_CHANNELS; nChn++)
2084 	{
2085 		ModChannel &chn = m_PlayState.Chn[nChn];
2086 		// FT2 Compatibility: Prevent notes to be stopped after a fadeout. This way, a portamento effect can pick up a faded instrument which is long enough.
2087 		// This occurs for example in the bassline (channel 11) of jt_burn.xm. I hope this won't break anything else...
2088 		// I also suppose this could decrease mixing performance a bit, but hey, which CPU can't handle 32 muted channels these days... :-)
2089 		if(chn.dwFlags[CHN_NOTEFADE] && (!(chn.nFadeOutVol|chn.leftVol|chn.rightVol)) && !m_playBehaviour[kFT2ProcessSilentChannels])
2090 		{
2091 			chn.nLength = 0;
2092 			chn.nROfs = chn.nLOfs = 0;
2093 		}
2094 		// Check for unused channel
2095 		if(chn.dwFlags[CHN_MUTE] || (nChn >= m_nChannels && !chn.nLength))
2096 		{
2097 			if(nChn < m_nChannels)
2098 			{
2099 				// Process MIDI macros on channels that are currently muted.
2100 				ProcessMacroOnChannel(nChn);
2101 			}
2102 			chn.nLeftVU = chn.nRightVU = 0;
2103 			continue;
2104 		}
2105 		// Reset channel data
2106 		chn.increment = SamplePosition(0);
2107 		chn.nRealVolume = 0;
2108 		chn.nCalcVolume = 0;
2109 
2110 		chn.nRampLength = 0;
2111 
2112 		//Aux variables
2113 		Tuning::RATIOTYPE vibratoFactor = 1;
2114 		Tuning::NOTEINDEXTYPE arpeggioSteps = 0;
2115 
2116 		const ModInstrument *pIns = chn.pModInstrument;
2117 
2118 		// Calc Frequency
2119 		int32 period = 0;
2120 
2121 		// Also process envelopes etc. when there's a plugin on this channel, for possible fake automation using volume and pan data.
2122 		// We only care about master channels, though, since automation only "happens" on them.
2123 		const bool samplePlaying = (chn.nPeriod && chn.nLength);
2124 		const bool plugAssigned = (nChn < m_nChannels) && (ChnSettings[nChn].nMixPlugin || (chn.pModInstrument != nullptr && chn.pModInstrument->nMixPlug));
2125 		if (samplePlaying || plugAssigned)
2126 		{
2127 			int vol = chn.nVolume;
2128 			int insVol = chn.nInsVol;		// This is the "SV * IV" value in ITTECH.TXT
2129 
2130 			ProcessVolumeSwing(chn, m_playBehaviour[kITSwingBehaviour] ? insVol : vol);
2131 			ProcessPanningSwing(chn);
2132 			ProcessTremolo(chn, vol);
2133 			ProcessTremor(nChn, vol);
2134 
2135 			// Clip volume and multiply (extend to 14 bits)
2136 			Limit(vol, 0, 256);
2137 			vol <<= 6;
2138 
2139 			// Process Envelopes
2140 			if (pIns)
2141 			{
2142 				if(m_playBehaviour[kITEnvelopePositionHandling])
2143 				{
2144 					// In IT compatible mode, envelope position indices are shifted by one for proper envelope pausing,
2145 					// so we have to update the position before we actually process the envelopes.
2146 					// When using MPT behaviour, we get the envelope position for the next tick while we are still calculating the current tick,
2147 					// which then results in wrong position information when the envelope is paused on the next row.
2148 					// Test cases: s77.it
2149 					IncrementEnvelopePositions(chn);
2150 				}
2151 				ProcessVolumeEnvelope(chn, vol);
2152 				ProcessInstrumentFade(chn, vol);
2153 				ProcessPanningEnvelope(chn);
2154 
2155 				if(!m_playBehaviour[kITPitchPanSeparation] && chn.nNote != NOTE_NONE && chn.pModInstrument && chn.pModInstrument->nPPS != 0)
2156 					ProcessPitchPanSeparation(chn.nRealPan, chn.nNote, *chn.pModInstrument);
2157 			} else
2158 			{
2159 				// No Envelope: key off => note cut
2160 				if(chn.dwFlags[CHN_NOTEFADE]) // 1.41-: CHN_KEYOFF|CHN_NOTEFADE
2161 				{
2162 					chn.nFadeOutVol = 0;
2163 					vol = 0;
2164 				}
2165 			}
2166 
2167 			if(chn.isPaused)
2168 				vol = 0;
2169 
2170 			// vol is 14-bits
2171 			if (vol)
2172 			{
2173 				// IMPORTANT: chn.nRealVolume is 14 bits !!!
2174 				// -> Util::muldiv( 14+8, 6+6, 18); => RealVolume: 14-bit result (22+12-20)
2175 
2176 				if(chn.dwFlags[CHN_SYNCMUTE])
2177 				{
2178 					chn.nRealVolume = 0;
2179 				} else if (m_PlayConfig.getGlobalVolumeAppliesToMaster())
2180 				{
2181 					// Don't let global volume affect level of sample if
2182 					// Global volume is going to be applied to master output anyway.
2183 					chn.nRealVolume = Util::muldiv(vol * MAX_GLOBAL_VOLUME, chn.nGlobalVol * insVol, 1 << 20);
2184 				} else
2185 				{
2186 					chn.nRealVolume = Util::muldiv(vol * m_PlayState.m_nGlobalVolume, chn.nGlobalVol * insVol, 1 << 20);
2187 				}
2188 			}
2189 
2190 			chn.nCalcVolume = vol;	// Update calculated volume for MIDI macros
2191 
2192 			// ST3 only clamps the final output period, but never the channel's internal period.
2193 			// Test case: PeriodLimit.s3m
2194 			if (chn.nPeriod < m_nMinPeriod
2195 				&& GetType() != MOD_TYPE_S3M
2196 				&& !PeriodsAreFrequencies())
2197 			{
2198 				chn.nPeriod = m_nMinPeriod;
2199 			} else if(chn.nPeriod >= m_nMaxPeriod && m_playBehaviour[kApplyUpperPeriodLimit] && !PeriodsAreFrequencies())
2200 			{
2201 				// ...but on the other hand, ST3's SoundBlaster driver clamps the maximum channel period.
2202 				// Test case: PeriodLimitUpper.s3m
2203 				chn.nPeriod = m_nMaxPeriod;
2204 			}
2205 			if(m_playBehaviour[kFT2Periods]) Clamp(chn.nPeriod, 1, 31999);
2206 			period = chn.nPeriod;
2207 
2208 			// When glissando mode is set to semitones, clamp to the next halftone.
2209 			if((chn.dwFlags & (CHN_GLISSANDO | CHN_PORTAMENTO)) == (CHN_GLISSANDO | CHN_PORTAMENTO)
2210 				&& (!m_SongFlags[SONG_PT_MODE] || (chn.rowCommand.IsPortamento() && !m_SongFlags[SONG_FIRSTTICK])))
2211 			{
2212 				if(period != chn.cachedPeriod)
2213 				{
2214 					// Only recompute this whole thing in case the base period has changed.
2215 					chn.cachedPeriod = period;
2216 					chn.glissandoPeriod = GetPeriodFromNote(GetNoteFromPeriod(period, chn.nFineTune, chn.nC5Speed), chn.nFineTune, chn.nC5Speed);
2217 				}
2218 				period = chn.glissandoPeriod;
2219 			}
2220 
2221 			ProcessArpeggio(nChn, period, arpeggioSteps);
2222 
2223 			// Preserve Amiga freq limits.
2224 			// In ST3, the frequency is always clamped to periods 113 to 856, while in ProTracker,
2225 			// the limit is variable, depending on the finetune of the sample.
2226 			// The int32_max test is for the arpeggio wrap-around in ProcessArpeggio().
2227 			// Test case: AmigaLimits.s3m, AmigaLimitsFinetune.mod
2228 			if(m_SongFlags[SONG_AMIGALIMITS | SONG_PT_MODE] && period != int32_max)
2229 			{
2230 				int limitLow = 113 * 4, limitHigh = 856 * 4;
2231 				if(GetType() != MOD_TYPE_S3M)
2232 				{
2233 					const int tableOffset = XM2MODFineTune(chn.nFineTune) * 12;
2234 					limitLow = ProTrackerTunedPeriods[tableOffset +  11] / 2;
2235 					limitHigh = ProTrackerTunedPeriods[tableOffset] * 2;
2236 					// Amiga cannot actually keep up with lower periods
2237 					if(limitLow < 113 * 4) limitLow = 113 * 4;
2238 				}
2239 				Limit(period, limitLow, limitHigh);
2240 				Limit(chn.nPeriod, limitLow, limitHigh);
2241 			}
2242 
2243 			ProcessPanbrello(chn);
2244 		}
2245 
2246 		// IT Compatibility: Ensure that there is no pan swing, panbrello, panning envelopes, etc. applied on surround channels.
2247 		// Test case: surround-pan.it
2248 		if(chn.dwFlags[CHN_SURROUND] && !m_SongFlags[SONG_SURROUNDPAN] && m_playBehaviour[kITNoSurroundPan])
2249 		{
2250 			chn.nRealPan = 128;
2251 		}
2252 
2253 		// Now that all relevant envelopes etc. have been processed, we can parse the MIDI macro data.
2254 		ProcessMacroOnChannel(nChn);
2255 
2256 		// After MIDI macros have been processed, we can also process the pitch / filter envelope and other pitch-related things.
2257 		if(samplePlaying)
2258 		{
2259 			int cutoff = ProcessPitchFilterEnvelope(chn, period);
2260 			if(cutoff >= 0 && chn.dwFlags[CHN_ADLIB] && m_opl)
2261 			{
2262 				// Cutoff doubles as modulator intensity for FM instruments
2263 				m_opl->Volume(nChn, static_cast<uint8>(cutoff / 4), true);
2264 			}
2265 		}
2266 
2267 		if(chn.rowCommand.volcmd == VOLCMD_VIBRATODEPTH &&
2268 			(chn.rowCommand.command == CMD_VIBRATO || chn.rowCommand.command == CMD_VIBRATOVOL || chn.rowCommand.command == CMD_FINEVIBRATO))
2269 		{
2270 			if(GetType() == MOD_TYPE_XM)
2271 			{
2272 				// XM Compatibility: Vibrato should be advanced twice (but not added up) if both volume-column and effect column vibrato is present.
2273 				// Effect column vibrato parameter has precedence if non-zero.
2274 				// Test case: VibratoDouble.xm
2275 				if(!m_SongFlags[SONG_FIRSTTICK])
2276 					chn.nVibratoPos += chn.nVibratoSpeed;
2277 			} else if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))
2278 			{
2279 				// IT Compatibility: Vibrato should be applied twice if both volume-colum and effect column vibrato is present.
2280 				// Volume column vibrato parameter has precedence if non-zero.
2281 				// Test case: VibratoDouble.it
2282 				Vibrato(chn, chn.rowCommand.vol);
2283 				ProcessVibrato(nChn, period, vibratoFactor);
2284 			}
2285 		}
2286 		// Plugins may also receive vibrato
2287 		ProcessVibrato(nChn, period, vibratoFactor);
2288 
2289 		if(samplePlaying)
2290 		{
2291 			int nPeriodFrac = 0;
2292 			ProcessSampleAutoVibrato(chn, period, vibratoFactor, nPeriodFrac);
2293 
2294 			// Final Period
2295 			// ST3 only clamps the final output period, but never the channel's internal period.
2296 			// Test case: PeriodLimit.s3m
2297 			if (period <= m_nMinPeriod)
2298 			{
2299 				if(m_playBehaviour[kST3LimitPeriod]) chn.nLength = 0;	// Pattern 15 in watcha.s3m
2300 				period = m_nMinPeriod;
2301 			}
2302 
2303 			const bool hasTuning = chn.HasCustomTuning();
2304 			if(hasTuning)
2305 			{
2306 				if(chn.m_CalculateFreq || (chn.m_ReCalculateFreqOnFirstTick && m_PlayState.m_nTickCount == 0))
2307 				{
2308 					chn.RecalcTuningFreq(vibratoFactor, arpeggioSteps, *this);
2309 					if(!chn.m_CalculateFreq)
2310 						chn.m_ReCalculateFreqOnFirstTick = false;
2311 					else
2312 						chn.m_CalculateFreq = false;
2313 				}
2314 			}
2315 
2316 			auto [ninc, freq] = GetChannelIncrement(chn, period, nPeriodFrac);
2317 #ifndef MODPLUG_TRACKER
2318 			ninc.MulDiv(m_nFreqFactor, 65536);
2319 #endif  // !MODPLUG_TRACKER
2320 			if(ninc.IsZero())
2321 			{
2322 				ninc.Set(0, 1);
2323 			}
2324 			chn.increment = ninc;
2325 
2326 			if((chn.dwFlags & (CHN_ADLIB | CHN_MUTE | CHN_SYNCMUTE)) == CHN_ADLIB && m_opl)
2327 			{
2328 				const bool doProcess = m_playBehaviour[kOPLFlexibleNoteOff] || !chn.dwFlags[CHN_NOTEFADE] || GetType() == MOD_TYPE_S3M;
2329 				if(doProcess && !(GetType() == MOD_TYPE_S3M && chn.dwFlags[CHN_KEYOFF]))
2330 				{
2331 					// In ST3, a sample rate of 8363 Hz is mapped to middle-C, which is 261.625 Hz in a tempered scale at A4 = 440.
2332 					// Hence, we have to translate our "sample rate" into pitch.
2333 					auto milliHertz = Util::muldivr_unsigned(freq, 261625, 8363 << FREQ_FRACBITS);
2334 
2335 					const bool keyOff = chn.dwFlags[CHN_KEYOFF] || (chn.dwFlags[CHN_NOTEFADE] && chn.nFadeOutVol == 0);
2336 					if(!m_playBehaviour[kOPLNoteStopWith0Hz] || !keyOff)
2337 						m_opl->Frequency(nChn, milliHertz, keyOff, m_playBehaviour[kOPLBeatingOscillators]);
2338 				}
2339 				if(doProcess)
2340 				{
2341 					// Scale volume to OPL range (0...63).
2342 					m_opl->Volume(nChn, static_cast<uint8>(Util::muldivr_unsigned(chn.nCalcVolume * chn.nGlobalVol * chn.nInsVol, 63, 1 << 26)), false);
2343 					chn.nRealPan = m_opl->Pan(nChn, chn.nRealPan) * 128 + 128;
2344 				}
2345 
2346 				// Deallocate OPL channels for notes that are most definitely never going to play again.
2347 				if(const auto *ins = chn.pModInstrument; ins != nullptr
2348 					&& (ins->VolEnv.dwFlags & (ENV_ENABLED | ENV_LOOP | ENV_SUSTAIN)) == ENV_ENABLED
2349 					&& !ins->VolEnv.empty()
2350 					&& chn.GetEnvelope(ENV_VOLUME).nEnvPosition >= ins->VolEnv.back().tick
2351 					&& ins->VolEnv.back().value == 0)
2352 				{
2353 					m_opl->NoteCut(nChn);
2354 					if(!m_playBehaviour[kOPLNoResetAtEnvelopeEnd])
2355 						chn.dwFlags.reset(CHN_ADLIB);
2356 					chn.dwFlags.set(CHN_NOTEFADE);
2357 					chn.nFadeOutVol = 0;
2358 				} else if(m_playBehaviour[kOPLFlexibleNoteOff] && chn.dwFlags[CHN_NOTEFADE] && chn.nFadeOutVol == 0)
2359 				{
2360 					m_opl->NoteCut(nChn);
2361 					chn.dwFlags.reset(CHN_ADLIB);
2362 				}
2363 			}
2364 		}
2365 
2366 		// Increment envelope positions
2367 		if(pIns != nullptr && !m_playBehaviour[kITEnvelopePositionHandling])
2368 		{
2369 			// In IT and FT2 compatible mode, envelope positions are updated above.
2370 			// Test cases: s77.it, EnvLoops.xm
2371 			IncrementEnvelopePositions(chn);
2372 		}
2373 
2374 		// Volume ramping
2375 		chn.dwFlags.set(CHN_VOLUMERAMP, (chn.nRealVolume | chn.rightVol | chn.leftVol) != 0 && !chn.dwFlags[CHN_ADLIB]);
2376 
2377 		constexpr uint8 VUMETER_DECAY = 4;
2378 		chn.nLeftVU = (chn.nLeftVU > VUMETER_DECAY) ? (chn.nLeftVU - VUMETER_DECAY) : 0;
2379 		chn.nRightVU = (chn.nRightVU > VUMETER_DECAY) ? (chn.nRightVU - VUMETER_DECAY) : 0;
2380 
2381 		chn.newLeftVol = chn.newRightVol = 0;
2382 		chn.pCurrentSample = (chn.pModSample && chn.pModSample->HasSampleData() && chn.nLength && chn.IsSamplePlaying()) ? chn.pModSample->samplev() : nullptr;
2383 		if(chn.pCurrentSample || (chn.HasMIDIOutput() && !chn.dwFlags[CHN_KEYOFF | CHN_NOTEFADE]))
2384 		{
2385 			// Update VU-Meter (nRealVolume is 14-bit)
2386 			uint32 vul = (chn.nRealVolume * (256-chn.nRealPan)) / (1 << 14);
2387 			if (vul > 127) vul = 127;
2388 			if (chn.nLeftVU > 127) chn.nLeftVU = (uint8)vul;
2389 			vul /= 2;
2390 			if (chn.nLeftVU < vul) chn.nLeftVU = (uint8)vul;
2391 			uint32 vur = (chn.nRealVolume * chn.nRealPan) / (1 << 14);
2392 			if (vur > 127) vur = 127;
2393 			if (chn.nRightVU > 127) chn.nRightVU = (uint8)vur;
2394 			vur /= 2;
2395 			if (chn.nRightVU < vur) chn.nRightVU = (uint8)vur;
2396 		} else
2397 		{
2398 			// Note change but no sample
2399 			if (chn.nLeftVU > 128) chn.nLeftVU = 0;
2400 			if (chn.nRightVU > 128) chn.nRightVU = 0;
2401 		}
2402 
2403 		if (chn.pCurrentSample)
2404 		{
2405 #ifdef MODPLUG_TRACKER
2406 			const uint32 kChnMasterVol = chn.dwFlags[CHN_EXTRALOUD] ? (uint32)m_PlayConfig.getNormalSamplePreAmp() : nMasterVol;
2407 #else
2408 			const uint32 kChnMasterVol = nMasterVol;
2409 #endif // MODPLUG_TRACKER
2410 
2411 			// Adjusting volumes
2412 			{
2413 				int32 pan = (m_MixerSettings.gnChannels >= 2) ? Clamp(chn.nRealPan, 0, 256) : 128;
2414 
2415 				int32 realvol;
2416 				if(m_PlayConfig.getUseGlobalPreAmp())
2417 				{
2418 					realvol = (chn.nRealVolume * kChnMasterVol) / 128;
2419 				} else
2420 				{
2421 					// Extra attenuation required here if we're bypassing pre-amp.
2422 					realvol = (chn.nRealVolume * kChnMasterVol) / 256;
2423 				}
2424 
2425 				const PanningMode panningMode = m_PlayConfig.getPanningMode();
2426 				if(panningMode == PanningMode::SoftPanning || (panningMode == PanningMode::Undetermined && (m_MixerSettings.MixerFlags & SNDMIX_SOFTPANNING)))
2427 				{
2428 					if(pan < 128)
2429 					{
2430 						chn.newLeftVol = (realvol * 128) / 256;
2431 						chn.newRightVol = (realvol * pan) / 256;
2432 					} else
2433 					{
2434 						chn.newLeftVol = (realvol * (256 - pan)) / 256;
2435 						chn.newRightVol = (realvol * 128) / 256;
2436 					}
2437 				} else if(panningMode == PanningMode::FT2Panning)
2438 				{
2439 					// FT2 uses square root panning. There is a 257-entry LUT for this,
2440 					// but FT2's internal panning ranges from 0 to 255 only, meaning that
2441 					// you can never truly achieve 100% right panning in FT2, only 100% left.
2442 					// Test case: FT2PanLaw.xm
2443 					LimitMax(pan, 255);
2444 					const int panL = pan > 0 ? XMPanningTable[256 - pan] : 65536;
2445 					const int panR = XMPanningTable[pan];
2446 					chn.newLeftVol = (realvol * panL) / 65536;
2447 					chn.newRightVol = (realvol * panR) / 65536;
2448 				} else
2449 				{
2450 					chn.newLeftVol = (realvol * (256 - pan)) / 256;
2451 					chn.newRightVol = (realvol * pan) / 256;
2452 				}
2453 			}
2454 			// Clipping volumes
2455 			//if (chn.nNewRightVol > 0xFFFF) chn.nNewRightVol = 0xFFFF;
2456 			//if (chn.nNewLeftVol > 0xFFFF) chn.nNewLeftVol = 0xFFFF;
2457 
2458 			if(chn.pModInstrument && Resampling::IsKnownMode(chn.pModInstrument->resampling))
2459 			{
2460 				// For defined resampling modes, use per-instrument resampling mode if set
2461 				chn.resamplingMode = chn.pModInstrument->resampling;
2462 			} else if(Resampling::IsKnownMode(m_nResampling))
2463 			{
2464 				chn.resamplingMode = m_nResampling;
2465 			} else if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga != Resampling::AmigaFilter::Off)
2466 			{
2467 				// Enforce Amiga resampler for Amiga modules
2468 				chn.resamplingMode = SRCMODE_AMIGA;
2469 			} else
2470 			{
2471 				// Default to global mixer settings
2472 				chn.resamplingMode = m_Resampler.m_Settings.SrcMode;
2473 			}
2474 
2475 			if(chn.increment.IsUnity() && !(chn.dwFlags[CHN_VIBRATO] || chn.nAutoVibDepth || chn.resamplingMode == SRCMODE_AMIGA))
2476 			{
2477 				// Exact sample rate match, do not interpolate at all
2478 				// - unless vibrato is applied, because in this case the constant enabling and disabling
2479 				// of resampling can introduce clicks (this is easily observable with a sine sample
2480 				// played at the mix rate).
2481 				chn.resamplingMode = SRCMODE_NEAREST;
2482 			}
2483 
2484 			const int extraAttenuation = m_PlayConfig.getExtraSampleAttenuation();
2485 			chn.newLeftVol /= (1 << extraAttenuation);
2486 			chn.newRightVol /= (1 << extraAttenuation);
2487 
2488 			// Dolby Pro-Logic Surround
2489 			if(chn.dwFlags[CHN_SURROUND] && m_MixerSettings.gnChannels == 2) chn.newRightVol = -chn.newRightVol;
2490 
2491 			// Checking Ping-Pong Loops
2492 			if(chn.dwFlags[CHN_PINGPONGFLAG]) chn.increment.Negate();
2493 
2494 			// Setting up volume ramp
2495 			ProcessRamping(chn);
2496 
2497 			// Adding the channel in the channel list
2498 			if(!chn.dwFlags[CHN_ADLIB])
2499 			{
2500 				m_PlayState.ChnMix[m_nMixChannels++] = nChn;
2501 			}
2502 		} else
2503 		{
2504 			chn.rightVol = chn.leftVol = 0;
2505 			chn.nLength = 0;
2506 			// Put the channel back into the mixer for end-of-sample pop reduction
2507 			if(chn.nLOfs || chn.nROfs)
2508 				m_PlayState.ChnMix[m_nMixChannels++] = nChn;
2509 		}
2510 
2511 		chn.dwOldFlags = chn.dwFlags;
2512 	}
2513 
2514 	// If there are more channels being mixed than allowed, order them by volume and discard the most quiet ones
2515 	if(m_nMixChannels >= m_MixerSettings.m_nMaxMixChannels)
2516 	{
2517 		std::partial_sort(std::begin(m_PlayState.ChnMix), std::begin(m_PlayState.ChnMix) + m_MixerSettings.m_nMaxMixChannels, std::begin(m_PlayState.ChnMix) + m_nMixChannels,
2518 			[this](CHANNELINDEX i, CHANNELINDEX j) { return (m_PlayState.Chn[i].nRealVolume > m_PlayState.Chn[j].nRealVolume); });
2519 	}
2520 	return true;
2521 }
2522 
2523 
ProcessMacroOnChannel(CHANNELINDEX nChn)2524 void CSoundFile::ProcessMacroOnChannel(CHANNELINDEX nChn)
2525 {
2526 	ModChannel &chn = m_PlayState.Chn[nChn];
2527 	if(nChn < GetNumChannels())
2528 	{
2529 		// TODO evaluate per-plugin macros here
2530 		//ProcessMIDIMacro(nChn, false, m_MidiCfg.szMidiGlb[MIDIOUT_PAN]);
2531 		//ProcessMIDIMacro(nChn, false, m_MidiCfg.szMidiGlb[MIDIOUT_VOLUME]);
2532 
2533 		if((chn.rowCommand.command == CMD_MIDI && m_SongFlags[SONG_FIRSTTICK]) || chn.rowCommand.command == CMD_SMOOTHMIDI)
2534 		{
2535 			if(chn.rowCommand.param < 0x80)
2536 				ProcessMIDIMacro(nChn, (chn.rowCommand.command == CMD_SMOOTHMIDI), m_MidiCfg.szMidiSFXExt[chn.nActiveMacro], chn.rowCommand.param);
2537 			else
2538 				ProcessMIDIMacro(nChn, (chn.rowCommand.command == CMD_SMOOTHMIDI), m_MidiCfg.szMidiZXXExt[(chn.rowCommand.param & 0x7F)], 0);
2539 		}
2540 	}
2541 }
2542 
2543 
2544 #ifndef NO_PLUGINS
2545 
ProcessMidiOut(CHANNELINDEX nChn)2546 void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn)
2547 {
2548 	ModChannel &chn = m_PlayState.Chn[nChn];
2549 
2550 	// Do we need to process MIDI?
2551 	// For now there is no difference between mute and sync mute with VSTis.
2552 	if(chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE] || !chn.HasMIDIOutput()) return;
2553 
2554 	// Get instrument info and plugin reference
2555 	const ModInstrument *pIns = chn.pModInstrument;	// Can't be nullptr at this point, as we have valid MIDI output.
2556 
2557 	// No instrument or muted instrument?
2558 	if(pIns->dwFlags[INS_MUTE])
2559 	{
2560 		return;
2561 	}
2562 
2563 	// Check instrument plugins
2564 	const PLUGINDEX nPlugin = GetBestPlugin(nChn, PrioritiseInstrument, RespectMutes);
2565 	IMixPlugin *pPlugin = nullptr;
2566 	if(nPlugin > 0 && nPlugin <= MAX_MIXPLUGINS)
2567 	{
2568 		pPlugin = m_MixPlugins[nPlugin - 1].pMixPlugin;
2569 	}
2570 
2571 	// Couldn't find a valid plugin
2572 	if(pPlugin == nullptr) return;
2573 
2574 	const ModCommand::NOTE note = chn.rowCommand.note;
2575 	// Check for volume commands
2576 	uint8 vol = 0xFF;
2577 	if(chn.rowCommand.volcmd == VOLCMD_VOLUME)
2578 	{
2579 		vol = std::min(chn.rowCommand.vol, uint8(64));
2580 	} else if(chn.rowCommand.command == CMD_VOLUME)
2581 	{
2582 		vol = std::min(chn.rowCommand.param, uint8(64));
2583 	}
2584 	const bool hasVolCommand = (vol != 0xFF);
2585 
2586 	if(m_playBehaviour[kMIDICCBugEmulation])
2587 	{
2588 		if(note != NOTE_NONE)
2589 		{
2590 			ModCommand::NOTE realNote = note;
2591 			if(ModCommand::IsNote(note))
2592 				realNote = pIns->NoteMap[note - NOTE_MIN];
2593 			SendMIDINote(nChn, realNote, static_cast<uint16>(chn.nVolume));
2594 		} else if(hasVolCommand)
2595 		{
2596 			pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Fine, vol, nChn);
2597 		}
2598 		return;
2599 	}
2600 
2601 	const uint32 defaultVolume = pIns->nGlobalVol;
2602 
2603 	//If new note, determine notevelocity to use.
2604 	if(note != NOTE_NONE)
2605 	{
2606 		int32 velocity = static_cast<int32>(4 * defaultVolume);
2607 		switch(pIns->pluginVelocityHandling)
2608 		{
2609 			case PLUGIN_VELOCITYHANDLING_CHANNEL:
2610 				velocity = chn.nVolume;
2611 				break;
2612 			default:
2613 				break;
2614 		}
2615 
2616 		int32 swing = chn.nVolSwing;
2617 		if(m_playBehaviour[kITSwingBehaviour]) swing *= 4;
2618 		velocity += swing;
2619 		Limit(velocity, 0, 256);
2620 
2621 		ModCommand::NOTE realNote = note;
2622 		if(ModCommand::IsNote(note))
2623 			realNote = pIns->NoteMap[note - NOTE_MIN];
2624 		// Experimental VST panning
2625 		//ProcessMIDIMacro(nChn, false, m_MidiCfg.szMidiGlb[MIDIOUT_PAN], 0, nPlugin);
2626 		SendMIDINote(nChn, realNote, static_cast<uint16>(velocity));
2627 	}
2628 
2629 	const bool processVolumeAlsoOnNote = (pIns->pluginVelocityHandling == PLUGIN_VELOCITYHANDLING_VOLUME);
2630 	const bool hasNote = m_playBehaviour[kMIDIVolumeOnNoteOffBug] ? (note != NOTE_NONE) : ModCommand::IsNote(note);
2631 
2632 	if((hasVolCommand && !hasNote) || (hasNote && processVolumeAlsoOnNote))
2633 	{
2634 		switch(pIns->pluginVolumeHandling)
2635 		{
2636 			case PLUGIN_VOLUMEHANDLING_DRYWET:
2637 				if(hasVolCommand) pPlugin->SetDryRatio(2 * vol);
2638 				else pPlugin->SetDryRatio(2 * defaultVolume);
2639 				break;
2640 			case PLUGIN_VOLUMEHANDLING_MIDI:
2641 				if(hasVolCommand) pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Coarse, std::min(uint8(127), static_cast<uint8>(2 * vol)), nChn);
2642 				else pPlugin->MidiCC(MIDIEvents::MIDICC_Volume_Coarse, static_cast<uint8>(std::min(uint32(127), static_cast<uint32>(2 * defaultVolume))), nChn);
2643 				break;
2644 			default:
2645 				break;
2646 		}
2647 	}
2648 }
2649 
2650 #endif // NO_PLUGINS
2651 
2652 
2653 template<int channels>
ApplyGlobalVolumeWithRamping(int32 * SoundBuffer,int32 * RearBuffer,int32 lCount,int32 m_nGlobalVolume,int32 step,int32 & m_nSamplesToGlobalVolRampDest,int32 & m_lHighResRampingGlobalVolume)2654 MPT_FORCEINLINE void ApplyGlobalVolumeWithRamping(int32 *SoundBuffer, int32 *RearBuffer, int32 lCount, int32 m_nGlobalVolume, int32 step, int32 &m_nSamplesToGlobalVolRampDest, int32 &m_lHighResRampingGlobalVolume)
2655 {
2656 	const bool isStereo = (channels >= 2);
2657 	const bool hasRear = (channels >= 4);
2658 	for(int pos = 0; pos < lCount; ++pos)
2659 	{
2660 		if(m_nSamplesToGlobalVolRampDest > 0)
2661 		{
2662 			// Ramping required
2663 			m_lHighResRampingGlobalVolume += step;
2664 			                          SoundBuffer[0] = Util::muldiv(SoundBuffer[0], m_lHighResRampingGlobalVolume, MAX_GLOBAL_VOLUME << VOLUMERAMPPRECISION);
2665 			if constexpr(isStereo) SoundBuffer[1] = Util::muldiv(SoundBuffer[1], m_lHighResRampingGlobalVolume, MAX_GLOBAL_VOLUME << VOLUMERAMPPRECISION);
2666 			if constexpr(hasRear)  RearBuffer[0]  = Util::muldiv(RearBuffer[0] , m_lHighResRampingGlobalVolume, MAX_GLOBAL_VOLUME << VOLUMERAMPPRECISION); else MPT_UNUSED_VARIABLE(RearBuffer);
2667 			if constexpr(hasRear)  RearBuffer[1]  = Util::muldiv(RearBuffer[1] , m_lHighResRampingGlobalVolume, MAX_GLOBAL_VOLUME << VOLUMERAMPPRECISION); else MPT_UNUSED_VARIABLE(RearBuffer);
2668 			m_nSamplesToGlobalVolRampDest--;
2669 		} else
2670 		{
2671 			                          SoundBuffer[0] = Util::muldiv(SoundBuffer[0], m_nGlobalVolume, MAX_GLOBAL_VOLUME);
2672 			if constexpr(isStereo) SoundBuffer[1] = Util::muldiv(SoundBuffer[1], m_nGlobalVolume, MAX_GLOBAL_VOLUME);
2673 			if constexpr(hasRear)  RearBuffer[0]  = Util::muldiv(RearBuffer[0] , m_nGlobalVolume, MAX_GLOBAL_VOLUME); else MPT_UNUSED_VARIABLE(RearBuffer);
2674 			if constexpr(hasRear)  RearBuffer[1]  = Util::muldiv(RearBuffer[1] , m_nGlobalVolume, MAX_GLOBAL_VOLUME); else MPT_UNUSED_VARIABLE(RearBuffer);
2675 			m_lHighResRampingGlobalVolume = m_nGlobalVolume << VOLUMERAMPPRECISION;
2676 		}
2677 		SoundBuffer += isStereo ? 2 : 1;
2678 		if constexpr(hasRear) RearBuffer += 2;
2679 	}
2680 }
2681 
2682 
ProcessGlobalVolume(long lCount)2683 void CSoundFile::ProcessGlobalVolume(long lCount)
2684 {
2685 
2686 	// should we ramp?
2687 	if(IsGlobalVolumeUnset())
2688 	{
2689 		// do not ramp if no global volume was set before (which is the case at song start), to prevent audible glitches when default volume is > 0 and it is set to 0 in the first row
2690 		m_PlayState.m_nGlobalVolumeDestination = m_PlayState.m_nGlobalVolume;
2691 		m_PlayState.m_nSamplesToGlobalVolRampDest = 0;
2692 		m_PlayState.m_nGlobalVolumeRampAmount = 0;
2693 	} else if(m_PlayState.m_nGlobalVolumeDestination != m_PlayState.m_nGlobalVolume)
2694 	{
2695 		// User has provided new global volume
2696 
2697 		// m_nGlobalVolume: the last global volume which got set e.g. by a pattern command
2698 		// m_nGlobalVolumeDestination: the current target of the ramping algorithm
2699 		const bool rampUp = m_PlayState.m_nGlobalVolume > m_PlayState.m_nGlobalVolumeDestination;
2700 
2701 		m_PlayState.m_nGlobalVolumeDestination = m_PlayState.m_nGlobalVolume;
2702 		m_PlayState.m_nSamplesToGlobalVolRampDest = m_PlayState.m_nGlobalVolumeRampAmount = rampUp ? m_MixerSettings.GetVolumeRampUpSamples() : m_MixerSettings.GetVolumeRampDownSamples();
2703 	}
2704 
2705 	// calculate ramping step
2706 	int32 step = 0;
2707 	if (m_PlayState.m_nSamplesToGlobalVolRampDest > 0)
2708 	{
2709 
2710 		// Still some ramping left to do.
2711 		int32 highResGlobalVolumeDestination = static_cast<int32>(m_PlayState.m_nGlobalVolumeDestination) << VOLUMERAMPPRECISION;
2712 
2713 		const long delta = highResGlobalVolumeDestination - m_PlayState.m_lHighResRampingGlobalVolume;
2714 		step = delta / static_cast<long>(m_PlayState.m_nSamplesToGlobalVolRampDest);
2715 
2716 		if(m_nMixLevels == MixLevels::v1_17RC2)
2717 		{
2718 			// Define max step size as some factor of user defined ramping value: the lower the value, the more likely the click.
2719 			// If step is too big (might cause click), extend ramp length.
2720 			// Warning: This increases the volume ramp length by EXTREME amounts (factors of 100 are easily reachable)
2721 			// compared to the user-defined setting, so this really should not be used!
2722 			int32 maxStep = std::max(int32(50), static_cast<int32>((10000 / (m_PlayState.m_nGlobalVolumeRampAmount + 1))));
2723 			while(std::abs(step) > maxStep)
2724 			{
2725 				m_PlayState.m_nSamplesToGlobalVolRampDest += m_PlayState.m_nGlobalVolumeRampAmount;
2726 				step = delta / static_cast<int32>(m_PlayState.m_nSamplesToGlobalVolRampDest);
2727 			}
2728 		}
2729 	}
2730 
2731 	// apply volume and ramping
2732 	if(m_MixerSettings.gnChannels == 1)
2733 	{
2734 		ApplyGlobalVolumeWithRamping<1>(MixSoundBuffer, MixRearBuffer, lCount, m_PlayState.m_nGlobalVolume, step, m_PlayState.m_nSamplesToGlobalVolRampDest, m_PlayState.m_lHighResRampingGlobalVolume);
2735 	} else if(m_MixerSettings.gnChannels == 2)
2736 	{
2737 		ApplyGlobalVolumeWithRamping<2>(MixSoundBuffer, MixRearBuffer, lCount, m_PlayState.m_nGlobalVolume, step, m_PlayState.m_nSamplesToGlobalVolRampDest, m_PlayState.m_lHighResRampingGlobalVolume);
2738 	} else if(m_MixerSettings.gnChannels == 4)
2739 	{
2740 		ApplyGlobalVolumeWithRamping<4>(MixSoundBuffer, MixRearBuffer, lCount, m_PlayState.m_nGlobalVolume, step, m_PlayState.m_nSamplesToGlobalVolRampDest, m_PlayState.m_lHighResRampingGlobalVolume);
2741 	}
2742 
2743 }
2744 
2745 
ProcessStereoSeparation(long countChunk)2746 void CSoundFile::ProcessStereoSeparation(long countChunk)
2747 {
2748 	ApplyStereoSeparation(MixSoundBuffer, MixRearBuffer, m_MixerSettings.gnChannels, countChunk, m_MixerSettings.m_nStereoSeparation);
2749 }
2750 
2751 
2752 OPENMPT_NAMESPACE_END
2753