1 /*
2  * Sndfile.cpp
3  * -----------
4  * Purpose: Core class of the playback engine. Every song is represented by a CSoundFile object.
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 #ifdef MODPLUG_TRACKER
14 #include "../mptrack/Mptrack.h"	// For CTrackApp::OpenURL
15 #include "../mptrack/TrackerSettings.h"
16 #include "../mptrack/Moddoc.h"
17 #include "../mptrack/Reporting.h"
18 #include "../mptrack/Mainfrm.h"
19 #endif // MODPLUG_TRACKER
20 #ifdef MPT_EXTERNAL_SAMPLES
21 #include "../common/mptFileIO.h"
22 #endif // MPT_EXTERNAL_SAMPLES
23 #include "../common/version.h"
24 #include "../soundlib/AudioCriticalSection.h"
25 #include "../common/serialization_utils.h"
26 #include "Sndfile.h"
27 #include "Tables.h"
28 #include "mod_specifications.h"
29 #include "tuningcollection.h"
30 #include "plugins/PluginManager.h"
31 #include "plugins/PlugInterface.h"
32 #include "../common/mptStringBuffer.h"
33 #include "../common/FileReader.h"
34 #include "Container.h"
35 #include "OPL.h"
36 #include "mpt/io/io.hpp"
37 #include "mpt/io/io_stdstream.hpp"
38 
39 #ifndef NO_ARCHIVE_SUPPORT
40 #include "../unarchiver/unarchiver.h"
41 #endif // NO_ARCHIVE_SUPPORT
42 
43 
44 OPENMPT_NAMESPACE_BEGIN
45 
46 
SettingCacheCompleteFileBeforeLoading()47 bool SettingCacheCompleteFileBeforeLoading()
48 {
49 	#ifdef MODPLUG_TRACKER
50 		return TrackerSettings::Instance().MiscCacheCompleteFileBeforeLoading;
51 	#else
52 		return false;
53 	#endif
54 }
55 
56 
AsISO8601() const57 mpt::ustring FileHistory::AsISO8601() const
58 {
59 	tm date = loadDate;
60 	if(openTime > 0)
61 	{
62 		// Calculate the date when editing finished.
63 		double openSeconds = static_cast<double>(openTime) / HISTORY_TIMER_PRECISION;
64 		tm tmpLoadDate = loadDate;
65 		int64 loadDateSinceEpoch = mpt::Date::Unix::FromUTC(tmpLoadDate);
66 		int64 saveDateSinceEpoch = loadDateSinceEpoch + mpt::saturate_round<int64>(openSeconds);
67 		date = mpt::Date::Unix(saveDateSinceEpoch).AsUTC();
68 	}
69 	return mpt::Date::ToShortenedISO8601(date);
70 }
71 
72 
73 //////////////////////////////////////////////////////////
74 // CSoundFile
75 
76 #ifdef MODPLUG_TRACKER
77 const NoteName *CSoundFile::m_NoteNames = NoteNamesFlat;
78 #endif
79 
CSoundFile()80 CSoundFile::CSoundFile() :
81 #ifndef MODPLUG_TRACKER
82 	m_NoteNames(NoteNamesSharp),
83 #endif
84 	m_pModSpecs(&ModSpecs::itEx),
85 	m_nType(MOD_TYPE_NONE),
86 	Patterns(*this),
87 #ifdef MODPLUG_TRACKER
88 	m_MIDIMapper(*this),
89 #endif
90 	Order(*this),
91 	m_PRNG(mpt::make_prng<mpt::fast_prng>(mpt::global_prng())),
92 	m_visitedRows(*this)
93 {
94 	MemsetZero(MixSoundBuffer);
95 	MemsetZero(MixRearBuffer);
96 	MemsetZero(MixFloatBuffer);
97 
98 #ifdef MODPLUG_TRACKER
99 	m_bChannelMuteTogglePending.reset();
100 
101 	m_nDefaultRowsPerBeat = m_PlayState.m_nCurrentRowsPerBeat = (TrackerSettings::Instance().m_nRowHighlightBeats) ? TrackerSettings::Instance().m_nRowHighlightBeats : 4;
102 	m_nDefaultRowsPerMeasure = m_PlayState.m_nCurrentRowsPerMeasure = (TrackerSettings::Instance().m_nRowHighlightMeasures >= m_nDefaultRowsPerBeat) ? TrackerSettings::Instance().m_nRowHighlightMeasures : m_nDefaultRowsPerBeat * 4;
103 #else
104 	m_nDefaultRowsPerBeat = m_PlayState.m_nCurrentRowsPerBeat = 4;
105 	m_nDefaultRowsPerMeasure = m_PlayState.m_nCurrentRowsPerMeasure = 16;
106 #endif // MODPLUG_TRACKER
107 
108 	MemsetZero(Instruments);
109 	Clear(m_szNames);
110 
111 	m_pTuningsTuneSpecific = new CTuningCollection();
112 }
113 
114 
~CSoundFile()115 CSoundFile::~CSoundFile()
116 {
117 	Destroy();
118 	delete m_pTuningsTuneSpecific;
119 	m_pTuningsTuneSpecific = nullptr;
120 }
121 
122 
AddToLog(LogLevel level,const mpt::ustring & text) const123 void CSoundFile::AddToLog(LogLevel level, const mpt::ustring &text) const
124 {
125 	if(m_pCustomLog)
126 	{
127 		m_pCustomLog->AddToLog(level, text);
128 	} else
129 	{
130 		#ifdef MODPLUG_TRACKER
131 			if(GetpModDoc()) GetpModDoc()->AddToLog(level, text);
132 		#else
133 			MPT_LOG_GLOBAL(level, "soundlib", text);
134 		#endif
135 	}
136 }
137 
138 
139 // Global variable initializer for loader functions
InitializeGlobals(MODTYPE type)140 void CSoundFile::InitializeGlobals(MODTYPE type)
141 {
142 	// Do not add or change any of these values! And if you do, review each and every loader to check if they require these defaults!
143 	m_nType = type;
144 
145 	MODTYPE bestType = GetBestSaveFormat();
146 	m_playBehaviour = GetDefaultPlaybackBehaviour(bestType);
147 	SetModSpecsPointer(m_pModSpecs, bestType);
148 
149 	// Delete instruments in case some previously called loader already created them.
150 	for(INSTRUMENTINDEX i = 1; i <= m_nInstruments; i++)
151 	{
152 		delete Instruments[i];
153 		Instruments[i] = nullptr;
154 	}
155 
156 	m_ContainerType = MOD_CONTAINERTYPE_NONE;
157 	m_nChannels = 0;
158 	m_nInstruments = 0;
159 	m_nSamples = 0;
160 	m_nSamplePreAmp = 48;
161 	m_nVSTiVolume = 48;
162 	m_OPLVolumeFactor = m_OPLVolumeFactorScale;
163 	m_nDefaultSpeed = 6;
164 	m_nDefaultTempo.Set(125);
165 	m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME;
166 	m_SongFlags.reset();
167 	m_nMinPeriod = 16;
168 	m_nMaxPeriod = 32767;
169 	m_nResampling = SRCMODE_DEFAULT;
170 	m_dwLastSavedWithVersion = Version(0);
171 	m_dwCreatedWithVersion = Version(0);
172 
173 	SetMixLevels(MixLevels::Compatible);
174 
175 	Patterns.ClearPatterns();
176 	Order.Initialize();
177 
178 	m_songName.clear();
179 	m_songArtist.clear();
180 	m_songMessage.clear();
181 	m_modFormat = ModFormatDetails();
182 	m_FileHistory.clear();
183 	m_tempoSwing.clear();
184 #ifdef MPT_EXTERNAL_SAMPLES
185 	m_samplePaths.clear();
186 #endif // MPT_EXTERNAL_SAMPLES
187 
188 	// Note: we do not use the Amiga resampler for DBM as it's a multichannel format and can make use of higher-quality Amiga soundcards instead of Paula.
189 	if(GetType() & (/*MOD_TYPE_DBM | */MOD_TYPE_DIGI | MOD_TYPE_MED | MOD_TYPE_MOD | MOD_TYPE_OKT | MOD_TYPE_SFX | MOD_TYPE_STP))
190 	{
191 		m_SongFlags.set(SONG_ISAMIGA);
192 	}
193 }
194 
195 
InitializeChannels()196 void CSoundFile::InitializeChannels()
197 {
198 	for(CHANNELINDEX nChn = 0; nChn < MAX_BASECHANNELS; nChn++)
199 	{
200 		InitChannel(nChn);
201 	}
202 }
203 
204 
205 struct FileFormatLoader
206 {
207 	decltype(CSoundFile::ProbeFileHeaderXM) *prober;
208 	decltype(&CSoundFile::ReadXM) loader;
209 };
210 
211 #ifdef MODPLUG_TRACKER
212 #define MPT_DECLARE_FORMAT(format) { nullptr, &CSoundFile::Read ## format }
213 #else
214 #define MPT_DECLARE_FORMAT(format) { CSoundFile::ProbeFileHeader ## format, &CSoundFile::Read ## format }
215 #endif
216 
217 // All module format loaders, in the order they should be executed.
218 // This order matters, depending on the format, due to some unfortunate
219 // clashes or lack of magic bytes that can lead to mis-detection of some formats.
220 // Apart from that, more common formats with sane magic bytes are also found
221 // at the top of the list to match the most common cases more quickly.
222 static constexpr FileFormatLoader ModuleFormatLoaders[] =
223 {
224 	MPT_DECLARE_FORMAT(XM),
225 	MPT_DECLARE_FORMAT(IT),
226 	MPT_DECLARE_FORMAT(S3M),
227 	MPT_DECLARE_FORMAT(STM),
228 	MPT_DECLARE_FORMAT(MED),
229 	MPT_DECLARE_FORMAT(MTM),
230 	MPT_DECLARE_FORMAT(MDL),
231 	MPT_DECLARE_FORMAT(DBM),
232 	MPT_DECLARE_FORMAT(FAR),
233 	MPT_DECLARE_FORMAT(AMS),
234 	MPT_DECLARE_FORMAT(AMS2),
235 	MPT_DECLARE_FORMAT(OKT),
236 	MPT_DECLARE_FORMAT(PTM),
237 	MPT_DECLARE_FORMAT(ULT),
238 	MPT_DECLARE_FORMAT(DMF),
239 	MPT_DECLARE_FORMAT(DSM),
240 	MPT_DECLARE_FORMAT(AMF_Asylum),
241 	MPT_DECLARE_FORMAT(AMF_DSMI),
242 	MPT_DECLARE_FORMAT(PSM),
243 	MPT_DECLARE_FORMAT(PSM16),
244 	MPT_DECLARE_FORMAT(MT2),
245 	MPT_DECLARE_FORMAT(ITP),
246 #if defined(MODPLUG_TRACKER) || defined(MPT_FUZZ_TRACKER)
247 	// These make little sense for a module player library
248 	MPT_DECLARE_FORMAT(UAX),
249 	MPT_DECLARE_FORMAT(WAV),
250 	MPT_DECLARE_FORMAT(MID),
251 #endif // MODPLUG_TRACKER || MPT_FUZZ_TRACKER
252 	MPT_DECLARE_FORMAT(GDM),
253 	MPT_DECLARE_FORMAT(IMF),
254 	MPT_DECLARE_FORMAT(DIGI),
255 	MPT_DECLARE_FORMAT(DTM),
256 	MPT_DECLARE_FORMAT(PLM),
257 	MPT_DECLARE_FORMAT(AM),
258 	MPT_DECLARE_FORMAT(J2B),
259 	MPT_DECLARE_FORMAT(PT36),
260 	MPT_DECLARE_FORMAT(SymMOD),
261 	MPT_DECLARE_FORMAT(MUS_KM),
262 	MPT_DECLARE_FORMAT(FMT),
263 	MPT_DECLARE_FORMAT(SFX),
264 	MPT_DECLARE_FORMAT(STP),
265 	MPT_DECLARE_FORMAT(DSym),
266 	MPT_DECLARE_FORMAT(STX),
267 	MPT_DECLARE_FORMAT(MOD),
268 	MPT_DECLARE_FORMAT(ICE),
269 	MPT_DECLARE_FORMAT(669),
270 	MPT_DECLARE_FORMAT(C67),
271 	MPT_DECLARE_FORMAT(MO3),
272 	MPT_DECLARE_FORMAT(M15),
273 };
274 
275 #undef MPT_DECLARE_FORMAT
276 
277 
ProbeAdditionalSize(MemoryFileReader & file,const uint64 * pfilesize,uint64 minimumAdditionalSize)278 CSoundFile::ProbeResult CSoundFile::ProbeAdditionalSize(MemoryFileReader &file, const uint64 *pfilesize, uint64 minimumAdditionalSize)
279 {
280 	const uint64 availableFileSize = file.GetLength();
281 	const uint64 fileSize = (pfilesize ? *pfilesize : file.GetLength());
282 	//const uint64 validFileSize = std::min(fileSize, static_cast<uint64>(ProbeRecommendedSize));
283 	const uint64 goalSize = file.GetPosition() + minimumAdditionalSize;
284 	//const uint64 goalMinimumSize = std::min(goalSize, static_cast<uint64>(ProbeRecommendedSize));
285 	if(pfilesize)
286 	{
287 		if(availableFileSize < std::min(fileSize, static_cast<uint64>(ProbeRecommendedSize)))
288 		{
289 			if(availableFileSize < goalSize)
290 			{
291 				return ProbeWantMoreData;
292 			}
293 		} else
294 		{
295 			if(fileSize < goalSize)
296 			{
297 				return ProbeFailure;
298 			}
299 		}
300 		return ProbeSuccess;
301 	}
302 	return ProbeSuccess;
303 }
304 
305 
306 #define MPT_DO_PROBE( storedResult , call ) \
307 	do { \
308 		ProbeResult lastResult = call ; \
309 		if(lastResult == ProbeSuccess) { \
310 			return ProbeSuccess; \
311 		} else if(lastResult == ProbeWantMoreData) { \
312 			storedResult = ProbeWantMoreData; \
313 		} \
314 	} while(0) \
315 /**/
316 
317 
Probe(ProbeFlags flags,mpt::span<const std::byte> data,const uint64 * pfilesize)318 CSoundFile::ProbeResult CSoundFile::Probe(ProbeFlags flags, mpt::span<const std::byte> data, const uint64 *pfilesize)
319 {
320 	ProbeResult result = ProbeFailure;
321 	if(pfilesize && (*pfilesize < data.size()))
322 	{
323 		throw std::out_of_range("");
324 	}
325 	if(!data.data())
326 	{
327 		throw std::invalid_argument("");
328 	}
329 	MemoryFileReader file(data);
330 	if(flags & ProbeContainers)
331 	{
332 #if !defined(MPT_WITH_ANCIENT)
333 		MPT_DO_PROBE(result, ProbeFileHeaderMMCMP(file, pfilesize));
334 		MPT_DO_PROBE(result, ProbeFileHeaderPP20(file, pfilesize));
335 		MPT_DO_PROBE(result, ProbeFileHeaderXPK(file, pfilesize));
336 #endif // !MPT_WITH_ANCIENT
337 		MPT_DO_PROBE(result, ProbeFileHeaderUMX(file, pfilesize));
338 	}
339 	if(flags & ProbeModules)
340 	{
341 		for(const auto &format : ModuleFormatLoaders)
342 		{
343 			if(format.prober != nullptr)
344 			{
345 				MPT_DO_PROBE(result, format.prober(file, pfilesize));
346 			}
347 		}
348 	}
349 	if(pfilesize)
350 	{
351 		if((result == ProbeWantMoreData) && (mpt::saturate_cast<std::size_t>(*pfilesize) <= data.size()))
352 		{
353 			// If the prober wants more data but we already reached EOF,
354 			// probing must fail.
355 			result = ProbeFailure;
356 		}
357 	} else
358 	{
359 		if((result == ProbeWantMoreData) && (data.size() >= ProbeRecommendedSize))
360 		{
361 			// If the prober wants more daat but we already provided the recommended required maximum,
362 			// just return success as this is the best we can do for the suggestesd probing size.
363 			result = ProbeSuccess;
364 		}
365 	}
366 	return result;
367 }
368 
369 
370 #ifdef MODPLUG_TRACKER
Create(FileReader file,ModLoadingFlags loadFlags,CModDoc * pModDoc)371 bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags, CModDoc *pModDoc)
372 {
373 	m_pModDoc = pModDoc;
374 #else
375 bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
376 {
377 #endif // MODPLUG_TRACKER
378 
379 	m_nMixChannels = 0;
380 #ifndef MODPLUG_TRACKER
381 	m_nFreqFactor = m_nTempoFactor = 65536;
382 #endif
383 
384 	MemsetZero(Instruments);
385 	Clear(m_szNames);
386 #ifndef NO_PLUGINS
387 	std::fill(std::begin(m_MixPlugins), std::end(m_MixPlugins), SNDMIXPLUGIN());
388 #endif // NO_PLUGINS
389 
390 	if(file.IsValid())
391 	{
392 
393 		{
394 
395 #ifndef NO_ARCHIVE_SUPPORT
396 			CUnarchiver unarchiver(file);
397 			if(!(loadFlags & skipContainer))
398 			{
399 				if (unarchiver.ExtractBestFile(GetSupportedExtensions(true)))
400 				{
401 					file = unarchiver.GetOutputFile();
402 				}
403 			}
404 #endif
405 
406 			std::vector<ContainerItem> containerItems;
407 			MODCONTAINERTYPE packedContainerType = MOD_CONTAINERTYPE_NONE;
408 			if(!(loadFlags & skipContainer))
409 			{
410 				ContainerLoadingFlags containerLoadFlags = (loadFlags == onlyVerifyHeader) ? ContainerOnlyVerifyHeader : ContainerUnwrapData;
411 #if !defined(MPT_WITH_ANCIENT)
412 				if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackXPK(containerItems, file, containerLoadFlags)) packedContainerType = MOD_CONTAINERTYPE_XPK;
413 				if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackPP20(containerItems, file, containerLoadFlags)) packedContainerType = MOD_CONTAINERTYPE_PP20;
414 				if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackMMCMP(containerItems, file, containerLoadFlags)) packedContainerType = MOD_CONTAINERTYPE_MMCMP;
415 #endif // !MPT_WITH_ANCIENT
416 				if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackUMX(containerItems, file, containerLoadFlags)) packedContainerType = MOD_CONTAINERTYPE_UMX;
417 				if(packedContainerType != MOD_CONTAINERTYPE_NONE)
418 				{
419 					if(loadFlags == onlyVerifyHeader)
420 					{
421 						return true;
422 					}
423 					if(!containerItems.empty())
424 					{
425 						// cppcheck false-positive
426 						// cppcheck-suppress containerOutOfBounds
427 						file = containerItems[0].file;
428 					}
429 				}
430 			}
431 
432 			if(loadFlags & skipModules)
433 			{
434 				return false;
435 			}
436 
437 			// Try all module format loaders
438 			bool loaderSuccess = false;
439 			for(const auto &format : ModuleFormatLoaders)
440 			{
441 				loaderSuccess = (this->*(format.loader))(file, loadFlags);
442 				if(loaderSuccess)
443 					break;
444 			}
445 
446 			if(!loaderSuccess)
447 			{
448 				m_nType = MOD_TYPE_NONE;
449 				m_ContainerType = MOD_CONTAINERTYPE_NONE;
450 			}
451 			if(loadFlags == onlyVerifyHeader)
452 			{
453 				return loaderSuccess;
454 			}
455 
456 			if(packedContainerType != MOD_CONTAINERTYPE_NONE && m_ContainerType == MOD_CONTAINERTYPE_NONE)
457 			{
458 				m_ContainerType = packedContainerType;
459 			}
460 
461 #ifndef NO_ARCHIVE_SUPPORT
462 			// Read archive comment if there is no song comment
463 			if(m_songMessage.empty())
464 			{
465 				m_songMessage.assign(mpt::ToCharset(mpt::Charset::Locale, unarchiver.GetComment()));
466 			}
467 #endif
468 
469 			m_visitedRows.Initialize(true);
470 
471 		}
472 	} else
473 	{
474 		// New song
475 		InitializeGlobals();
476 		m_visitedRows.Initialize(true);
477 		m_dwCreatedWithVersion = Version::Current();
478 	}
479 
480 	// Adjust channels
481 	const auto muteFlag = GetChannelMuteFlag();
482 	for(CHANNELINDEX chn = 0; chn < MAX_BASECHANNELS; chn++)
483 	{
484 		LimitMax(ChnSettings[chn].nVolume, uint16(64));
485 		if(ChnSettings[chn].nPan > 256)
486 			ChnSettings[chn].nPan = 128;
487 		if(ChnSettings[chn].nMixPlugin > MAX_MIXPLUGINS)
488 			ChnSettings[chn].nMixPlugin = 0;
489 		m_PlayState.Chn[chn].Reset(ModChannel::resetTotal, *this, chn, muteFlag);
490 	}
491 
492 	// Checking samples, load external samples
493 	for(SAMPLEINDEX nSmp = 1; nSmp <= m_nSamples; nSmp++)
494 	{
495 		ModSample &sample = Samples[nSmp];
496 
497 #ifdef MPT_EXTERNAL_SAMPLES
498 		if(SampleHasPath(nSmp))
499 		{
500 			mpt::PathString filename = GetSamplePath(nSmp);
501 			if(file.GetOptionalFileName())
502 			{
503 				filename = filename.RelativePathToAbsolute(file.GetOptionalFileName()->GetPath());
504 			} else if(GetpModDoc() != nullptr)
505 			{
506 				filename = filename.RelativePathToAbsolute(GetpModDoc()->GetPathNameMpt().GetPath());
507 			}
508 			filename = filename.Simplify();
509 			if(!LoadExternalSample(nSmp, filename))
510 			{
511 #ifndef MODPLUG_TRACKER
512 				// OpenMPT has its own way of reporting this error in CModDoc.
513 				AddToLog(LogError, MPT_UFORMAT("Unable to load sample {}: {}")(i, filename.ToUnicode()));
514 #endif // MODPLUG_TRACKER
515 			}
516 		} else
517 		{
518 			sample.uFlags.reset(SMP_KEEPONDISK);
519 		}
520 #endif // MPT_EXTERNAL_SAMPLES
521 
522 		if(sample.HasSampleData())
523 		{
524 			sample.PrecomputeLoops(*this, false);
525 		} else if(!sample.uFlags[SMP_KEEPONDISK])
526 		{
527 			sample.nLength = 0;
528 			sample.nLoopStart = 0;
529 			sample.nLoopEnd = 0;
530 			sample.nSustainStart = 0;
531 			sample.nSustainEnd = 0;
532 			sample.uFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP | CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN);
533 		}
534 		if(sample.nGlobalVol > 64) sample.nGlobalVol = 64;
535 		if(sample.uFlags[CHN_ADLIB] && m_opl == nullptr) InitOPL();
536 	}
537 	// Check invalid instruments
538 	INSTRUMENTINDEX maxInstr = 0;
539 	for(INSTRUMENTINDEX i = 0; i <= m_nInstruments; i++)
540 	{
541 		if(Instruments[i] != nullptr)
542 		{
543 			maxInstr = i;
544 			Instruments[i]->Sanitize(GetType());
545 		}
546 	}
547 	m_nInstruments = maxInstr;
548 
549 	// Set default play state values
550 	if(!m_nDefaultTempo.GetInt())
551 		m_nDefaultTempo.Set(125);
552 	else
553 		LimitMax(m_nDefaultTempo, TEMPO(uint16_max, 0));
554 	if(!m_nDefaultSpeed)
555 		m_nDefaultSpeed = 6;
556 
557 	if(m_nDefaultRowsPerMeasure < m_nDefaultRowsPerBeat)
558 		m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat;
559 	LimitMax(m_nDefaultRowsPerBeat, MAX_ROWS_PER_BEAT);
560 	LimitMax(m_nDefaultRowsPerMeasure, MAX_ROWS_PER_BEAT);
561 	LimitMax(m_nDefaultGlobalVolume, MAX_GLOBAL_VOLUME);
562 	if(!m_tempoSwing.empty())
563 		m_tempoSwing.resize(m_nDefaultRowsPerBeat);
564 
565 	m_PlayState.m_nMusicSpeed = m_nDefaultSpeed;
566 	m_PlayState.m_nMusicTempo = m_nDefaultTempo;
567 	m_PlayState.m_nCurrentRowsPerBeat = m_nDefaultRowsPerBeat;
568 	m_PlayState.m_nCurrentRowsPerMeasure = m_nDefaultRowsPerMeasure;
569 	m_PlayState.m_nGlobalVolume = static_cast<int32>(m_nDefaultGlobalVolume);
570 	m_PlayState.ResetGlobalVolumeRamping();
571 	m_PlayState.m_nNextOrder = 0;
572 	m_PlayState.m_nCurrentOrder = 0;
573 	m_PlayState.m_nPattern = 0;
574 	m_PlayState.m_nBufferCount = 0;
575 	m_PlayState.m_dBufferDiff = 0;
576 	m_PlayState.m_nTickCount = TICKS_ROW_FINISHED;
577 	m_PlayState.m_nNextRow = 0;
578 	m_PlayState.m_nRow = 0;
579 	m_PlayState.m_nPatternDelay = 0;
580 	m_PlayState.m_nFrameDelay = 0;
581 	m_PlayState.m_nextPatStartRow = 0;
582 	m_PlayState.m_nSeqOverride = ORDERINDEX_INVALID;
583 
584 	if(UseFinetuneAndTranspose())
585 		m_playBehaviour.reset(kPeriodsAreHertz);
586 
587 	m_nMaxOrderPosition = 0;
588 
589 	RecalculateSamplesPerTick();
590 
591 	for(auto &order : Order)
592 	{
593 		order.Shrink();
594 		if(order.GetRestartPos() >= order.size())
595 		{
596 			order.SetRestartPos(0);
597 		}
598 	}
599 
600 	if(GetType() == MOD_TYPE_NONE)
601 	{
602 		return false;
603 	}
604 
605 	SetModSpecsPointer(m_pModSpecs, GetBestSaveFormat());
606 
607 	// When reading a file made with an older version of MPT, it might be necessary to upgrade some settings automatically.
608 	if(m_dwLastSavedWithVersion)
609 	{
610 		UpgradeModule();
611 	}
612 
613 #ifndef NO_PLUGINS
614 	// Load plugins
615 #ifdef MODPLUG_TRACKER
616 	mpt::ustring notFoundText;
617 #endif // MODPLUG_TRACKER
618 	std::vector<const SNDMIXPLUGININFO *> notFoundIDs;
619 
620 	if((loadFlags & (loadPluginData | loadPluginInstance)) == (loadPluginData | loadPluginInstance))
621 	{
622 		for(PLUGINDEX plug = 0; plug < MAX_MIXPLUGINS; plug++)
623 		{
624 			auto &plugin = m_MixPlugins[plug];
625 			if(plugin.IsValidPlugin())
626 			{
627 #ifdef MODPLUG_TRACKER
628 				// Provide some visual feedback
629 				{
630 					mpt::ustring s = MPT_UFORMAT("Loading Plugin FX{}: {} ({})")(
631 						mpt::ufmt::dec0<2>(plug + 1),
632 						mpt::ToUnicode(mpt::Charset::UTF8, plugin.Info.szLibraryName),
633 						mpt::ToUnicode(mpt::Charset::Locale, plugin.Info.szName));
634 					CMainFrame::GetMainFrame()->SetHelpText(mpt::ToCString(s));
635 				}
636 #endif // MODPLUG_TRACKER
637 				CreateMixPluginProc(plugin, *this);
638 				if(plugin.pMixPlugin)
639 				{
640 					// Plugin was found
641 					plugin.pMixPlugin->RestoreAllParameters(plugin.defaultProgram);
642 				} else
643 				{
644 					// Plugin not found - add to list
645 					bool found = std::find_if(notFoundIDs.cbegin(), notFoundIDs.cend(),
646 						[&plugin](const SNDMIXPLUGININFO *info) { return info->dwPluginId2 == plugin.Info.dwPluginId2 && info->dwPluginId1 == plugin.Info.dwPluginId1; }) != notFoundIDs.cend();
647 
648 					if(!found)
649 					{
650 						notFoundIDs.push_back(&plugin.Info);
651 #ifdef MODPLUG_TRACKER
652 						notFoundText.append(plugin.GetLibraryName());
653 						notFoundText.append(UL_("\n"));
654 #else
655 						AddToLog(LogWarning, U_("Plugin not found: ") + plugin.GetLibraryName());
656 #endif // MODPLUG_TRACKER
657 					}
658 				}
659 			}
660 		}
661 	}
662 
663 	// Set up mix levels (also recalculates plugin mix levels - must be done after plugins were loaded)
664 	SetMixLevels(m_nMixLevels);
665 
666 #ifdef MODPLUG_TRACKER
667 	// Display a nice message so the user sees which plugins are missing
668 	// TODO: Use IDD_MODLOADING_WARNINGS dialog (NON-MODAL!) to display all warnings that are encountered when loading a module.
669 	if(!notFoundIDs.empty())
670 	{
671 		if(notFoundIDs.size() == 1)
672 		{
673 			notFoundText = UL_("The following plugin has not been found:\n\n") + notFoundText + UL_("\nDo you want to search for it online?");
674 		} else
675 		{
676 			notFoundText = UL_("The following plugins have not been found:\n\n") + notFoundText + UL_("\nDo you want to search for them online?");
677 		}
678 		if(Reporting::Confirm(notFoundText, U_("OpenMPT - Plugins missing"), false, true) == cnfYes)
679 		{
680 			mpt::ustring url = U_("https://resources.openmpt.org/plugins/search.php?p=");
681 			for(const auto &id : notFoundIDs)
682 			{
683 				url += mpt::ufmt::HEX0<8>(id->dwPluginId2.get());
684 				url += mpt::ToUnicode(mpt::Charset::UTF8, id->szLibraryName);
685 				url += UL_("%0a");
686 			}
687 			CTrackApp::OpenURL(mpt::PathString::FromUnicode(url));
688 		}
689 	}
690 #endif // MODPLUG_TRACKER
691 #endif // NO_PLUGINS
692 
693 	return true;
694 }
695 
696 
697 bool CSoundFile::Destroy()
698 {
699 	for(auto &chn : m_PlayState.Chn)
700 	{
701 		chn.pModInstrument = nullptr;
702 		chn.pModSample = nullptr;
703 		chn.pCurrentSample = nullptr;
704 		chn.nLength = 0;
705 	}
706 
707 	Patterns.DestroyPatterns();
708 
709 	m_songName.clear();
710 	m_songArtist.clear();
711 	m_songMessage.clear();
712 	m_FileHistory.clear();
713 #ifdef MPT_EXTERNAL_SAMPLES
714 	m_samplePaths.clear();
715 #endif // MPT_EXTERNAL_SAMPLES
716 
717 	for(auto &smp : Samples)
718 	{
719 		smp.FreeSample();
720 	}
721 	for(auto &ins : Instruments)
722 	{
723 		delete ins;
724 		ins = nullptr;
725 	}
726 #ifndef NO_PLUGINS
727 	for(auto &plug : m_MixPlugins)
728 	{
729 		plug.Destroy();
730 	}
731 #endif // NO_PLUGINS
732 
733 	m_nType = MOD_TYPE_NONE;
734 	m_ContainerType = MOD_CONTAINERTYPE_NONE;
735 	m_nChannels = m_nSamples = m_nInstruments = 0;
736 	return true;
737 }
738 
739 
740 //////////////////////////////////////////////////////////////////////////
741 // Misc functions
742 
743 
744 void CSoundFile::SetDspEffects(uint32 DSPMask)
745 {
746 	m_MixerSettings.DSPMask = DSPMask;
747 	InitPlayer(false);
748 }
749 
750 
751 void CSoundFile::SetPreAmp(uint32 nVol)
752 {
753 	if (nVol < 1) nVol = 1;
754 	if (nVol > 0x200) nVol = 0x200;	// x4 maximum
755 #ifndef NO_AGC
756 	if ((nVol < m_MixerSettings.m_nPreAmp) && (nVol) && (m_MixerSettings.DSPMask & SNDDSP_AGC))
757 	{
758 		m_AGC.Adjust(m_MixerSettings.m_nPreAmp, nVol);
759 	}
760 #endif
761 	m_MixerSettings.m_nPreAmp = nVol;
762 }
763 
764 
765 double CSoundFile::GetCurrentBPM() const
766 {
767 	double bpm;
768 
769 	if (m_nTempoMode == TempoMode::Modern)
770 	{
771 		// With modern mode, we trust that true bpm is close enough to what user chose.
772 		// This avoids oscillation due to tick-to-tick corrections.
773 		bpm = m_PlayState.m_nMusicTempo.ToDouble();
774 	} else
775 	{
776 		//with other modes, we calculate it:
777 		double ticksPerBeat = m_PlayState.m_nMusicSpeed * m_PlayState.m_nCurrentRowsPerBeat; //ticks/beat = ticks/row * rows/beat
778 		double samplesPerBeat = m_PlayState.m_nSamplesPerTick * ticksPerBeat;                //samps/beat = samps/tick * ticks/beat
779 		bpm =  m_MixerSettings.gdwMixingFreq / samplesPerBeat * 60;                          //beats/sec  = samps/sec  / samps/beat
780 	}	                                                                                     //beats/min  =  beats/sec * 60
781 
782 	return bpm;
783 }
784 
785 
786 void CSoundFile::ResetPlayPos()
787 {
788 	const auto muteFlag = GetChannelMuteFlag();
789 	for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
790 		m_PlayState.Chn[i].Reset(ModChannel::resetSetPosFull, *this, i, muteFlag);
791 
792 	m_visitedRows.Initialize(true);
793 	m_SongFlags.reset(SONG_FADINGSONG | SONG_ENDREACHED);
794 
795 	m_PlayState.m_nGlobalVolume = m_nDefaultGlobalVolume;
796 	m_PlayState.m_nMusicSpeed = m_nDefaultSpeed;
797 	m_PlayState.m_nMusicTempo = m_nDefaultTempo;
798 
799 	// Do not ramp global volume when starting playback
800 	m_PlayState.ResetGlobalVolumeRamping();
801 
802 	m_PlayState.m_nNextOrder = 0;
803 	m_PlayState.m_nNextRow = 0;
804 	m_PlayState.m_nTickCount = TICKS_ROW_FINISHED;
805 	m_PlayState.m_nBufferCount = 0;
806 	m_PlayState.m_nPatternDelay = 0;
807 	m_PlayState.m_nFrameDelay = 0;
808 	m_PlayState.m_nextPatStartRow = 0;
809 	m_PlayState.m_lTotalSampleCount = 0;
810 }
811 
812 
813 
814 void CSoundFile::SetCurrentOrder(ORDERINDEX nOrder)
815 {
816 	while(nOrder < Order().size() && !Order().IsValidPat(nOrder))
817 		nOrder++;
818 	if(nOrder >= Order().size())
819 		return;
820 
821 	for(auto &chn : m_PlayState.Chn)
822 	{
823 		chn.nPeriod = 0;
824 		chn.nNote = NOTE_NONE;
825 		chn.nPortamentoDest = 0;
826 		chn.nCommand = 0;
827 		chn.nPatternLoopCount = 0;
828 		chn.nPatternLoop = 0;
829 		chn.nVibratoPos = chn.nTremoloPos = chn.nPanbrelloPos = 0;
830 		//IT compatibility 15. Retrigger
831 		if(m_playBehaviour[kITRetrigger])
832 		{
833 			chn.nRetrigCount = 0;
834 			chn.nRetrigParam = 1;
835 		}
836 		chn.nTremorCount = 0;
837 	}
838 
839 #ifndef NO_PLUGINS
840 	// Stop hanging notes from VST instruments as well
841 	StopAllVsti();
842 #endif // NO_PLUGINS
843 
844 	if (!nOrder)
845 	{
846 		ResetPlayPos();
847 	} else
848 	{
849 		m_PlayState.m_nNextOrder = nOrder;
850 		m_PlayState.m_nRow = m_PlayState.m_nNextRow = 0;
851 		m_PlayState.m_nPattern = 0;
852 		m_PlayState.m_nTickCount = TICKS_ROW_FINISHED;
853 		m_PlayState.m_nBufferCount = 0;
854 		m_PlayState.m_nPatternDelay = 0;
855 		m_PlayState.m_nFrameDelay = 0;
856 		m_PlayState.m_nextPatStartRow = 0;
857 	}
858 
859 	m_SongFlags.reset(SONG_FADINGSONG | SONG_ENDREACHED);
860 }
861 
862 void CSoundFile::SuspendPlugins()
863 {
864 #ifndef NO_PLUGINS
865 	for(auto &plug : m_MixPlugins)
866 	{
867 		IMixPlugin *pPlugin = plug.pMixPlugin;
868 		if(pPlugin != nullptr && pPlugin->IsResumed())
869 		{
870 			pPlugin->NotifySongPlaying(false);
871 			pPlugin->HardAllNotesOff();
872 			pPlugin->Suspend();
873 		}
874 	}
875 #endif // NO_PLUGINS
876 }
877 
878 void CSoundFile::ResumePlugins()
879 {
880 #ifndef NO_PLUGINS
881 	for(auto &plugin : m_MixPlugins)
882 	{
883 		IMixPlugin *pPlugin = plugin.pMixPlugin;
884 		if(pPlugin != nullptr && !pPlugin->IsResumed())
885 		{
886 			pPlugin->NotifySongPlaying(true);
887 			pPlugin->Resume();
888 		}
889 	}
890 #endif // NO_PLUGINS
891 }
892 
893 
894 void CSoundFile::StopAllVsti()
895 {
896 #ifndef NO_PLUGINS
897 	for(auto &plugin : m_MixPlugins)
898 	{
899 		IMixPlugin *pPlugin = plugin.pMixPlugin;
900 		if(pPlugin != nullptr && pPlugin->IsResumed())
901 		{
902 			pPlugin->HardAllNotesOff();
903 		}
904 	}
905 #endif // NO_PLUGINS
906 }
907 
908 
909 void CSoundFile::SetMixLevels(MixLevels levels)
910 {
911 	m_nMixLevels = levels;
912 	m_PlayConfig.SetMixLevels(m_nMixLevels);
913 	RecalculateGainForAllPlugs();
914 }
915 
916 
917 void CSoundFile::RecalculateGainForAllPlugs()
918 {
919 #ifndef NO_PLUGINS
920 	for(auto &plugin : m_MixPlugins)
921 	{
922 		if(plugin.pMixPlugin != nullptr)
923 			plugin.pMixPlugin->RecalculateGain();
924 	}
925 #endif // NO_PLUGINS
926 }
927 
928 
929 void CSoundFile::ResetChannels()
930 {
931 	m_SongFlags.reset(SONG_FADINGSONG | SONG_ENDREACHED);
932 	m_PlayState.m_nBufferCount = 0;
933 	for(auto &chn : m_PlayState.Chn)
934 	{
935 		chn.nROfs = chn.nLOfs = 0;
936 		chn.nLength = 0;
937 		if(chn.dwFlags[CHN_ADLIB] && m_opl)
938 		{
939 			CHANNELINDEX c = static_cast<CHANNELINDEX>(std::distance(std::begin(m_PlayState.Chn), &chn));
940 			m_opl->NoteCut(c);
941 		}
942 	}
943 }
944 
945 
946 #ifdef MODPLUG_TRACKER
947 
948 void CSoundFile::PatternTranstionChnSolo(const CHANNELINDEX chnIndex)
949 {
950 	if(chnIndex >= m_nChannels)
951 		return;
952 
953 	for(CHANNELINDEX i = 0; i < m_nChannels; i++)
954 	{
955 		m_bChannelMuteTogglePending[i] = !ChnSettings[i].dwFlags[CHN_MUTE];
956 	}
957 	m_bChannelMuteTogglePending[chnIndex] = ChnSettings[chnIndex].dwFlags[CHN_MUTE];
958 }
959 
960 
961 void CSoundFile::PatternTransitionChnUnmuteAll()
962 {
963 	for(CHANNELINDEX i = 0; i < m_nChannels; i++)
964 	{
965 		m_bChannelMuteTogglePending[i] = ChnSettings[i].dwFlags[CHN_MUTE];
966 	}
967 }
968 
969 #endif // MODPLUG_TRACKER
970 
971 
972 void CSoundFile::LoopPattern(PATTERNINDEX nPat, ROWINDEX nRow)
973 {
974 	if(!Patterns.IsValidPat(nPat))
975 	{
976 		m_SongFlags.reset(SONG_PATTERNLOOP);
977 	} else
978 	{
979 		if(nRow >= Patterns[nPat].GetNumRows()) nRow = 0;
980 		m_PlayState.m_nPattern = nPat;
981 		m_PlayState.m_nRow = m_PlayState.m_nNextRow = nRow;
982 		m_PlayState.m_nTickCount = TICKS_ROW_FINISHED;
983 		m_PlayState.m_nPatternDelay = 0;
984 		m_PlayState.m_nFrameDelay = 0;
985 		m_PlayState.m_nextPatStartRow = 0;
986 		m_SongFlags.set(SONG_PATTERNLOOP);
987 	}
988 	m_PlayState.m_nBufferCount = 0;
989 }
990 
991 
992 void CSoundFile::DontLoopPattern(PATTERNINDEX nPat, ROWINDEX nRow)
993 {
994 	if(!Patterns.IsValidPat(nPat)) nPat = 0;
995 	if(nRow >= Patterns[nPat].GetNumRows()) nRow = 0;
996 	m_PlayState.m_nPattern = nPat;
997 	m_PlayState.m_nRow = m_PlayState.m_nNextRow = nRow;
998 	m_PlayState.m_nTickCount = TICKS_ROW_FINISHED;
999 	m_PlayState.m_nPatternDelay = 0;
1000 	m_PlayState.m_nFrameDelay = 0;
1001 	m_PlayState.m_nBufferCount = 0;
1002 	m_PlayState.m_nextPatStartRow = 0;
1003 	m_SongFlags.reset(SONG_PATTERNLOOP);
1004 }
1005 
1006 
1007 void CSoundFile::SetDefaultPlaybackBehaviour(MODTYPE type)
1008 {
1009 	m_playBehaviour = GetDefaultPlaybackBehaviour(type);
1010 }
1011 
1012 
1013 PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
1014 {
1015 	PlayBehaviourSet playBehaviour;
1016 	switch(type)
1017 	{
1018 	case MOD_TYPE_MPT:
1019 	case MOD_TYPE_IT:
1020 		playBehaviour.set(MSF_COMPATIBLE_PLAY);
1021 		playBehaviour.set(kPeriodsAreHertz);
1022 		playBehaviour.set(kTempoClamp);
1023 		playBehaviour.set(kPerChannelGlobalVolSlide);
1024 		playBehaviour.set(kPanOverride);
1025 		playBehaviour.set(kITInstrWithoutNote);
1026 		playBehaviour.set(kITVolColFinePortamento);
1027 		playBehaviour.set(kITArpeggio);
1028 		playBehaviour.set(kITOutOfRangeDelay);
1029 		playBehaviour.set(kITPortaMemoryShare);
1030 		playBehaviour.set(kITPatternLoopTargetReset);
1031 		playBehaviour.set(kITFT2PatternLoop);
1032 		playBehaviour.set(kITPingPongNoReset);
1033 		playBehaviour.set(kITEnvelopeReset);
1034 		playBehaviour.set(kITClearOldNoteAfterCut);
1035 		playBehaviour.set(kITVibratoTremoloPanbrello);
1036 		playBehaviour.set(kITTremor);
1037 		playBehaviour.set(kITRetrigger);
1038 		playBehaviour.set(kITMultiSampleBehaviour);
1039 		playBehaviour.set(kITPortaTargetReached);
1040 		playBehaviour.set(kITPatternLoopBreak);
1041 		playBehaviour.set(kITOffset);
1042 		playBehaviour.set(kITSwingBehaviour);
1043 		playBehaviour.set(kITNNAReset);
1044 		playBehaviour.set(kITSCxStopsSample);
1045 		playBehaviour.set(kITEnvelopePositionHandling);
1046 		playBehaviour.set(kITPortamentoInstrument);
1047 		playBehaviour.set(kITPingPongMode);
1048 		playBehaviour.set(kITRealNoteMapping);
1049 		playBehaviour.set(kITHighOffsetNoRetrig);
1050 		playBehaviour.set(kITFilterBehaviour);
1051 		playBehaviour.set(kITNoSurroundPan);
1052 		playBehaviour.set(kITShortSampleRetrig);
1053 		playBehaviour.set(kITPortaNoNote);
1054 		playBehaviour.set(kITFT2DontResetNoteOffOnPorta);
1055 		playBehaviour.set(kITVolColMemory);
1056 		playBehaviour.set(kITPortamentoSwapResetsPos);
1057 		playBehaviour.set(kITEmptyNoteMapSlot);
1058 		playBehaviour.set(kITFirstTickHandling);
1059 		playBehaviour.set(kITSampleAndHoldPanbrello);
1060 		playBehaviour.set(kITClearPortaTarget);
1061 		playBehaviour.set(kITPanbrelloHold);
1062 		playBehaviour.set(kITPanningReset);
1063 		playBehaviour.set(kITPatternLoopWithJumps);
1064 		playBehaviour.set(kITInstrWithNoteOff);
1065 		playBehaviour.set(kITMultiSampleInstrumentNumber);
1066 		playBehaviour.set(kRowDelayWithNoteDelay);
1067 		playBehaviour.set(kITInstrWithNoteOffOldEffects);
1068 		playBehaviour.set(kITDoNotOverrideChannelPan);
1069 		playBehaviour.set(kITDCTBehaviour);
1070 		playBehaviour.set(kITPitchPanSeparation);
1071 		if(type == MOD_TYPE_MPT)
1072 		{
1073 			playBehaviour.set(kOPLFlexibleNoteOff);
1074 			playBehaviour.set(kOPLwithNNA);
1075 			playBehaviour.set(kOPLNoteOffOnNoteChange);
1076 		}
1077 		break;
1078 
1079 	case MOD_TYPE_XM:
1080 		playBehaviour.set(MSF_COMPATIBLE_PLAY);
1081 		playBehaviour.set(kFT2VolumeRamping);
1082 		playBehaviour.set(kTempoClamp);
1083 		playBehaviour.set(kPerChannelGlobalVolSlide);
1084 		playBehaviour.set(kPanOverride);
1085 		playBehaviour.set(kITFT2PatternLoop);
1086 		playBehaviour.set(kITFT2DontResetNoteOffOnPorta);
1087 		playBehaviour.set(kFT2Arpeggio);
1088 		playBehaviour.set(kFT2Retrigger);
1089 		playBehaviour.set(kFT2VolColVibrato);
1090 		playBehaviour.set(kFT2PortaNoNote);
1091 		playBehaviour.set(kFT2KeyOff);
1092 		playBehaviour.set(kFT2PanSlide);
1093 		playBehaviour.set(kFT2ST3OffsetOutOfRange);
1094 		playBehaviour.set(kFT2RestrictXCommand);
1095 		playBehaviour.set(kFT2RetrigWithNoteDelay);
1096 		playBehaviour.set(kFT2SetPanEnvPos);
1097 		playBehaviour.set(kFT2PortaIgnoreInstr);
1098 		playBehaviour.set(kFT2VolColMemory);
1099 		playBehaviour.set(kFT2LoopE60Restart);
1100 		playBehaviour.set(kFT2ProcessSilentChannels);
1101 		playBehaviour.set(kFT2ReloadSampleSettings);
1102 		playBehaviour.set(kFT2PortaDelay);
1103 		playBehaviour.set(kFT2Transpose);
1104 		playBehaviour.set(kFT2PatternLoopWithJumps);
1105 		playBehaviour.set(kFT2PortaTargetNoReset);
1106 		playBehaviour.set(kFT2EnvelopeEscape);
1107 		playBehaviour.set(kFT2Tremor);
1108 		playBehaviour.set(kFT2OutOfRangeDelay);
1109 		playBehaviour.set(kFT2Periods);
1110 		playBehaviour.set(kFT2PanWithDelayedNoteOff);
1111 		playBehaviour.set(kFT2VolColDelay);
1112 		playBehaviour.set(kFT2FinetunePrecision);
1113 		playBehaviour.set(kFT2NoteOffFlags);
1114 		playBehaviour.set(kRowDelayWithNoteDelay);
1115 		playBehaviour.set(kFT2MODTremoloRampWaveform);
1116 		playBehaviour.set(kFT2PortaUpDownMemory);
1117 		playBehaviour.set(kFT2PanSustainRelease);
1118 		playBehaviour.set(kFT2NoteDelayWithoutInstr);
1119 		playBehaviour.set(kFT2PortaResetDirection);
1120 		break;
1121 
1122 	case MOD_TYPE_S3M:
1123 		playBehaviour.set(MSF_COMPATIBLE_PLAY);
1124 		playBehaviour.set(kTempoClamp);
1125 		playBehaviour.set(kPanOverride);
1126 		playBehaviour.set(kITPanbrelloHold);
1127 		playBehaviour.set(kFT2ST3OffsetOutOfRange);
1128 		playBehaviour.set(kST3NoMutedChannels);
1129 		playBehaviour.set(kST3PortaSampleChange);
1130 		playBehaviour.set(kST3EffectMemory);
1131 		playBehaviour.set(kST3VibratoMemory);
1132 		playBehaviour.set(KST3PortaAfterArpeggio);
1133 		playBehaviour.set(kRowDelayWithNoteDelay);
1134 		playBehaviour.set(kST3OffsetWithoutInstrument);
1135 		playBehaviour.set(kST3RetrigAfterNoteCut);
1136 		playBehaviour.set(kST3SampleSwap);
1137 		playBehaviour.set(kOPLNoteOffOnNoteChange);
1138 		playBehaviour.set(kApplyUpperPeriodLimit);
1139 		break;
1140 
1141 	case MOD_TYPE_MOD:
1142 		playBehaviour.set(kMODVBlankTiming);
1143 		playBehaviour.set(kMODOneShotLoops);
1144 		playBehaviour.set(kMODIgnorePanning);
1145 		playBehaviour.set(kMODSampleSwap);
1146 		playBehaviour.set(kMODOutOfRangeNoteDelay);
1147 		playBehaviour.set(kMODTempoOnSecondTick);
1148 		playBehaviour.set(kRowDelayWithNoteDelay);
1149 		playBehaviour.set(kFT2MODTremoloRampWaveform);
1150 		break;
1151 
1152 	default:
1153 		playBehaviour.set(MSF_COMPATIBLE_PLAY);
1154 		playBehaviour.set(kPeriodsAreHertz);
1155 		playBehaviour.set(kTempoClamp);
1156 		playBehaviour.set(kPanOverride);
1157 		break;
1158 	}
1159 	return playBehaviour;
1160 }
1161 
1162 
1163 PlayBehaviourSet CSoundFile::GetDefaultPlaybackBehaviour(MODTYPE type)
1164 {
1165 	PlayBehaviourSet playBehaviour;
1166 	switch(type)
1167 	{
1168 	case MOD_TYPE_MPT:
1169 		playBehaviour.set(kPeriodsAreHertz);
1170 		playBehaviour.set(kPerChannelGlobalVolSlide);
1171 		playBehaviour.set(kPanOverride);
1172 		playBehaviour.set(kITArpeggio);
1173 		playBehaviour.set(kITPortaMemoryShare);
1174 		playBehaviour.set(kITPatternLoopTargetReset);
1175 		playBehaviour.set(kITFT2PatternLoop);
1176 		playBehaviour.set(kITPingPongNoReset);
1177 		playBehaviour.set(kITClearOldNoteAfterCut);
1178 		playBehaviour.set(kITVibratoTremoloPanbrello);
1179 		playBehaviour.set(kITMultiSampleBehaviour);
1180 		playBehaviour.set(kITPortaTargetReached);
1181 		playBehaviour.set(kITPatternLoopBreak);
1182 		playBehaviour.set(kITSwingBehaviour);
1183 		playBehaviour.set(kITSCxStopsSample);
1184 		playBehaviour.set(kITEnvelopePositionHandling);
1185 		playBehaviour.set(kITPingPongMode);
1186 		playBehaviour.set(kITRealNoteMapping);
1187 		playBehaviour.set(kITPortaNoNote);
1188 		playBehaviour.set(kITVolColMemory);
1189 		playBehaviour.set(kITFirstTickHandling);
1190 		playBehaviour.set(kITClearPortaTarget);
1191 		playBehaviour.set(kITSampleAndHoldPanbrello);
1192 		playBehaviour.set(kITPanbrelloHold);
1193 		playBehaviour.set(kITPanningReset);
1194 		playBehaviour.set(kITInstrWithNoteOff);
1195 		playBehaviour.set(kOPLFlexibleNoteOff);
1196 		playBehaviour.set(kITDoNotOverrideChannelPan);
1197 		playBehaviour.set(kITDCTBehaviour);
1198 		playBehaviour.set(kOPLwithNNA);
1199 		playBehaviour.set(kITPitchPanSeparation);
1200 		break;
1201 
1202 	case MOD_TYPE_S3M:
1203 		playBehaviour = GetSupportedPlaybackBehaviour(type);
1204 		// Default behaviour was chosen to follow GUS, so kST3PortaSampleChange is enabled and kST3SampleSwap is disabled.
1205 		// For SoundBlaster behaviour, those two flags would need to be swapped.
1206 		playBehaviour.reset(kST3SampleSwap);
1207 		break;
1208 
1209 	case MOD_TYPE_XM:
1210 		playBehaviour = GetSupportedPlaybackBehaviour(type);
1211 		// Only set this explicitely for FT2-made XMs.
1212 		playBehaviour.reset(kFT2VolumeRamping);
1213 		break;
1214 
1215 	case MOD_TYPE_MOD:
1216 		playBehaviour.set(kRowDelayWithNoteDelay);
1217 		break;
1218 
1219 	default:
1220 		playBehaviour = GetSupportedPlaybackBehaviour(type);
1221 		break;
1222 	}
1223 	return playBehaviour;
1224 }
1225 
1226 
1227 MODTYPE CSoundFile::GetBestSaveFormat() const
1228 {
1229 	switch(GetType())
1230 	{
1231 	case MOD_TYPE_MOD:
1232 	case MOD_TYPE_S3M:
1233 	case MOD_TYPE_XM:
1234 	case MOD_TYPE_IT:
1235 	case MOD_TYPE_MPT:
1236 		return GetType();
1237 	case MOD_TYPE_AMF0:
1238 	case MOD_TYPE_DIGI:
1239 	case MOD_TYPE_SFX:
1240 	case MOD_TYPE_STP:
1241 		return MOD_TYPE_MOD;
1242 	case MOD_TYPE_MED:
1243 		if(!m_nInstruments)
1244 		{
1245 			for(const auto &pat : Patterns)
1246 			{
1247 				if(pat.IsValid() && pat.GetNumRows() != 64)
1248 					return MOD_TYPE_XM;
1249 			}
1250 			return MOD_TYPE_MOD;
1251 		}
1252 		return MOD_TYPE_XM;
1253 	case MOD_TYPE_PSM:
1254 		if(GetNumChannels() > 16)
1255 			return MOD_TYPE_IT;
1256 		for(CHANNELINDEX i = 0; i < GetNumChannels(); i++)
1257 		{
1258 			if(ChnSettings[i].dwFlags[CHN_SURROUND] || ChnSettings[i].nVolume != 64)
1259 			{
1260 				return MOD_TYPE_IT;
1261 				break;
1262 			}
1263 		}
1264 		return MOD_TYPE_S3M;
1265 	case MOD_TYPE_669:
1266 	case MOD_TYPE_FAR:
1267 	case MOD_TYPE_STM:
1268 	case MOD_TYPE_DSM:
1269 	case MOD_TYPE_AMF:
1270 	case MOD_TYPE_MTM:
1271 		return MOD_TYPE_S3M;
1272 	case MOD_TYPE_AMS:
1273 	case MOD_TYPE_DMF:
1274 	case MOD_TYPE_DBM:
1275 	case MOD_TYPE_IMF:
1276 	case MOD_TYPE_J2B:
1277 	case MOD_TYPE_ULT:
1278 	case MOD_TYPE_OKT:
1279 	case MOD_TYPE_MT2:
1280 	case MOD_TYPE_MDL:
1281 	case MOD_TYPE_PTM:
1282 	case MOD_TYPE_DTM:
1283 	default:
1284 		return MOD_TYPE_IT;
1285 	case MOD_TYPE_MID:
1286 		return MOD_TYPE_MPT;
1287 	}
1288 }
1289 
1290 
1291 const char *CSoundFile::GetSampleName(SAMPLEINDEX nSample) const
1292 {
1293 	MPT_ASSERT(nSample <= GetNumSamples());
1294 	if (nSample < MAX_SAMPLES)
1295 	{
1296 		return m_szNames[nSample].buf;
1297 	} else
1298 	{
1299 		return "";
1300 	}
1301 }
1302 
1303 
1304 const char *CSoundFile::GetInstrumentName(INSTRUMENTINDEX nInstr) const
1305 {
1306 	if((nInstr >= MAX_INSTRUMENTS) || (!Instruments[nInstr]))
1307 		return "";
1308 
1309 	MPT_ASSERT(nInstr <= GetNumInstruments());
1310 	return Instruments[nInstr]->name.buf;
1311 }
1312 
1313 
1314 bool CSoundFile::InitChannel(CHANNELINDEX nChn)
1315 {
1316 	if(nChn >= MAX_BASECHANNELS)
1317 		return true;
1318 
1319 	ChnSettings[nChn].Reset();
1320 	m_PlayState.Chn[nChn].Reset(ModChannel::resetTotal, *this, nChn, GetChannelMuteFlag());
1321 
1322 #ifdef MODPLUG_TRACKER
1323 	if(GetpModDoc() != nullptr)
1324 	{
1325 		GetpModDoc()->SetChannelRecordGroup(nChn, RecordGroup::NoGroup);
1326 	}
1327 #endif // MODPLUG_TRACKER
1328 
1329 #ifdef MODPLUG_TRACKER
1330 	m_bChannelMuteTogglePending[nChn] = false;
1331 #endif // MODPLUG_TRACKER
1332 
1333 	return false;
1334 }
1335 
1336 
1337 void CSoundFile::InitAmigaResampler()
1338 {
1339 	if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga != Resampling::AmigaFilter::Off)
1340 	{
1341 		const Paula::State defaultState(GetSampleRate());
1342 		for(auto &chn : m_PlayState.Chn)
1343 		{
1344 			chn.paulaState = defaultState;
1345 		}
1346 	}
1347 }
1348 
1349 
1350 void CSoundFile::InitOPL()
1351 {
1352 	if(!m_opl)
1353 		m_opl = std::make_unique<OPL>(m_MixerSettings.gdwMixingFreq);
1354 }
1355 
1356 
1357 // Detect samples that are referenced by an instrument, but actually not used in a song.
1358 // Only works in instrument mode. Unused samples are marked as false in the vector.
1359 SAMPLEINDEX CSoundFile::DetectUnusedSamples(std::vector<bool> &sampleUsed) const
1360 {
1361 	sampleUsed.assign(GetNumSamples() + 1, false);
1362 
1363 	if(GetNumInstruments() == 0)
1364 	{
1365 		return 0;
1366 	}
1367 	SAMPLEINDEX unused = 0;
1368 	std::vector<ModCommand::INSTR> lastIns;
1369 
1370 	for(const auto &pat : Patterns) if(pat.IsValid())
1371 	{
1372 		lastIns.assign(GetNumChannels(), 0);
1373 		auto p = pat.cbegin();
1374 		for(ROWINDEX row = 0; row < pat.GetNumRows(); row++)
1375 		{
1376 			for(CHANNELINDEX c = 0; c < GetNumChannels(); c++, p++)
1377 			{
1378 				if(p->IsNote())
1379 				{
1380 					ModCommand::INSTR instr = p->instr;
1381 					if(!p->instr)
1382 						instr = lastIns[c];
1383 					INSTRUMENTINDEX minInstr = 1, maxInstr = GetNumInstruments();
1384 					if(instr > 0)
1385 					{
1386 						if(instr <= GetNumInstruments())
1387 						{
1388 							minInstr = maxInstr = instr;
1389 						}
1390 						lastIns[c] = instr;
1391 					} else
1392 					{
1393 						// No idea which instrument this note belongs to, so mark it used in any instruments.
1394 					}
1395 					for(INSTRUMENTINDEX i = minInstr; i <= maxInstr; i++)
1396 					{
1397 						if(const auto *pIns = Instruments[i]; pIns != nullptr)
1398 						{
1399 							SAMPLEINDEX n = pIns->Keyboard[p->note - NOTE_MIN];
1400 							if(n <= GetNumSamples())
1401 								sampleUsed[n] = true;
1402 						}
1403 					}
1404 				}
1405 			}
1406 		}
1407 	}
1408 	for (SAMPLEINDEX ichk = GetNumSamples(); ichk >= 1; ichk--)
1409 	{
1410 		if ((!sampleUsed[ichk]) && (Samples[ichk].HasSampleData())) unused++;
1411 	}
1412 
1413 	return unused;
1414 }
1415 
1416 
1417 // Destroy samples where keepSamples index is false. First sample is keepSamples[1]!
1418 SAMPLEINDEX CSoundFile::RemoveSelectedSamples(const std::vector<bool> &keepSamples)
1419 {
1420 	if(keepSamples.empty())
1421 	{
1422 		return 0;
1423 	}
1424 
1425 	SAMPLEINDEX nRemoved = 0;
1426 	for(SAMPLEINDEX nSmp = std::min(GetNumSamples(), static_cast<SAMPLEINDEX>(keepSamples.size() - 1)); nSmp >= 1; nSmp--)
1427 	{
1428 		if(!keepSamples[nSmp])
1429 		{
1430 			CriticalSection cs;
1431 
1432 #ifdef MODPLUG_TRACKER
1433 			if(GetpModDoc())
1434 			{
1435 				GetpModDoc()->GetSampleUndo().PrepareUndo(nSmp, sundo_replace, "Remove Sample");
1436 			}
1437 #endif // MODPLUG_TRACKER
1438 
1439 			if(DestroySample(nSmp))
1440 			{
1441 				m_szNames[nSmp] = "";
1442 				nRemoved++;
1443 			}
1444 			if((nSmp == GetNumSamples()) && (nSmp > 1)) m_nSamples--;
1445 		}
1446 	}
1447 	return nRemoved;
1448 }
1449 
1450 
1451 bool CSoundFile::DestroySample(SAMPLEINDEX nSample)
1452 {
1453 	if(!nSample || nSample >= MAX_SAMPLES)
1454 	{
1455 		return false;
1456 	}
1457 	if(!Samples[nSample].HasSampleData())
1458 	{
1459 		return true;
1460 	}
1461 
1462 	ModSample &sample = Samples[nSample];
1463 
1464 	for(auto &chn : m_PlayState.Chn)
1465 	{
1466 		if(chn.pModSample == &sample)
1467 		{
1468 			chn.position.Set(0);
1469 			chn.nLength = 0;
1470 			chn.pCurrentSample = nullptr;
1471 		}
1472 	}
1473 
1474 	sample.FreeSample();
1475 	sample.nLength = 0;
1476 	sample.uFlags.reset(CHN_16BIT | CHN_STEREO);
1477 	sample.SetAdlib(false);
1478 
1479 #ifdef MODPLUG_TRACKER
1480 	ResetSamplePath(nSample);
1481 #endif
1482 	return true;
1483 }
1484 
1485 
1486 bool CSoundFile::DestroySampleThreadsafe(SAMPLEINDEX nSample)
1487 {
1488 	CriticalSection cs;
1489 	return DestroySample(nSample);
1490 }
1491 
1492 
1493 std::unique_ptr<CTuning> CSoundFile::CreateTuning12TET(const mpt::ustring &name)
1494 {
1495 	std::unique_ptr<CTuning> pT = CTuning::CreateGeometric(name, 12, 2, 15);
1496 	for(ModCommand::NOTE note = 0; note < 12; ++note)
1497 	{
1498 		pT->SetNoteName(note, mpt::ustring(NoteNamesSharp[note]));
1499 	}
1500 	return pT;
1501 }
1502 
1503 
1504 mpt::ustring CSoundFile::GetNoteName(const ModCommand::NOTE note, const INSTRUMENTINDEX inst) const
1505 {
1506 	// For MPTM instruments with custom tuning, find the appropriate note name. Else, use default note names.
1507 	if(ModCommand::IsNote(note) && GetType() == MOD_TYPE_MPT && inst >= 1 && inst <= GetNumInstruments() && Instruments[inst] && Instruments[inst]->pTuning)
1508 	{
1509 		return Instruments[inst]->pTuning->GetNoteName(note - NOTE_MIDDLEC);
1510 	} else
1511 	{
1512 		return GetNoteName(note);
1513 	}
1514 }
1515 
1516 
1517 mpt::ustring CSoundFile::GetNoteName(const ModCommand::NOTE note) const
1518 {
1519 	return GetNoteName(note, m_NoteNames);
1520 }
1521 
1522 
1523 mpt::ustring CSoundFile::GetNoteName(const ModCommand::NOTE note, const NoteName *noteNames)
1524 {
1525 	if(ModCommand::IsSpecialNote(note))
1526 	{
1527 		// cppcheck false-positive
1528 		// cppcheck-suppress constStatement
1529 		const mpt::uchar specialNoteNames[][4] = { UL_("PCs"), UL_("PC "), UL_("~~~"), UL_("^^^"), UL_("===") };
1530 		static_assert(mpt::array_size<decltype(specialNoteNames)>::size == NOTE_MAX_SPECIAL - NOTE_MIN_SPECIAL + 1);
1531 		return specialNoteNames[note - NOTE_MIN_SPECIAL];
1532 	} else if(ModCommand::IsNote(note))
1533 	{
1534 		return mpt::ustring()
1535 			.append(noteNames[(note - NOTE_MIN) % 12])
1536 			.append(1, UC_('0') + (note - NOTE_MIN) / 12)
1537 			;	// e.g. "C#" + "5"
1538 	} else if(note == NOTE_NONE)
1539 	{
1540 		return UL_("...");
1541 	}
1542 	return UL_("???");
1543 }
1544 
1545 
1546 #ifdef MODPLUG_TRACKER
1547 
1548 void CSoundFile::SetDefaultNoteNames()
1549 {
1550 	m_NoteNames = TrackerSettings::Instance().accidentalFlats ? NoteNamesFlat : NoteNamesSharp;
1551 }
1552 
1553 const NoteName *CSoundFile::GetDefaultNoteNames()
1554 {
1555 	return m_NoteNames;
1556 }
1557 
1558 #endif // MODPLUG_TRACKER
1559 
1560 
1561 void CSoundFile::SetModSpecsPointer(const CModSpecifications*& pModSpecs, const MODTYPE type)
1562 {
1563 	switch(type)
1564 	{
1565 		case MOD_TYPE_MPT:
1566 			pModSpecs = &ModSpecs::mptm;
1567 		break;
1568 
1569 		case MOD_TYPE_IT:
1570 			pModSpecs = &ModSpecs::itEx;
1571 		break;
1572 
1573 		case MOD_TYPE_XM:
1574 			pModSpecs = &ModSpecs::xmEx;
1575 		break;
1576 
1577 		case MOD_TYPE_S3M:
1578 			pModSpecs = &ModSpecs::s3mEx;
1579 		break;
1580 
1581 		case MOD_TYPE_MOD:
1582 		default:
1583 			pModSpecs = &ModSpecs::mod;
1584 			break;
1585 	}
1586 }
1587 
1588 
1589 void CSoundFile::SetType(MODTYPE type)
1590 {
1591 	m_nType = type;
1592 	m_playBehaviour = GetDefaultPlaybackBehaviour(GetBestSaveFormat());
1593 	SetModSpecsPointer(m_pModSpecs, GetBestSaveFormat());
1594 }
1595 
1596 
1597 #ifdef MODPLUG_TRACKER
1598 
1599 void CSoundFile::ChangeModTypeTo(const MODTYPE newType, bool adjust)
1600 {
1601 	const MODTYPE oldType = GetType();
1602 	m_nType = newType;
1603 	SetModSpecsPointer(m_pModSpecs, m_nType);
1604 
1605 	if(oldType == newType || !adjust)
1606 		return;
1607 
1608 	SetupMODPanning(); // Setup LRRL panning scheme if needed
1609 
1610 	// Only keep supported play behaviour flags
1611 	PlayBehaviourSet oldAllowedFlags = GetSupportedPlaybackBehaviour(oldType);
1612 	PlayBehaviourSet newAllowedFlags = GetSupportedPlaybackBehaviour(newType);
1613 	PlayBehaviourSet newDefaultFlags = GetDefaultPlaybackBehaviour(newType);
1614 	for(size_t i = 0; i < m_playBehaviour.size(); i++)
1615 	{
1616 		// If a flag is supported in both formats, keep its status
1617 		if(m_playBehaviour[i]) m_playBehaviour.set(i, newAllowedFlags[i]);
1618 		// Set allowed flags to their defaults if they were not supported in the old format
1619 		if(!oldAllowedFlags[i]) m_playBehaviour.set(i, newDefaultFlags[i]);
1620 	}
1621 	// Special case for OPL behaviour when converting from S3M to MPTM to retain S3M-like note-off behaviour
1622 	if(oldType == MOD_TYPE_S3M && newType == MOD_TYPE_MPT && m_opl)
1623 		m_playBehaviour.reset(kOPLFlexibleNoteOff);
1624 
1625 	Order.OnModTypeChanged(oldType);
1626 	Patterns.OnModTypeChanged(oldType);
1627 
1628 	m_modFormat.type = mpt::ToUnicode(mpt::Charset::UTF8, GetModSpecifications().fileExtension);
1629 }
1630 
1631 #endif // MODPLUG_TRACKER
1632 
1633 
1634 ModMessageHeuristicOrder CSoundFile::GetMessageHeuristic() const
1635 {
1636 	ModMessageHeuristicOrder result = ModMessageHeuristicOrder::Default;
1637 	switch(GetType())
1638 	{
1639 	case MOD_TYPE_MPT:
1640 		result = ModMessageHeuristicOrder::Samples;
1641 		break;
1642 	case MOD_TYPE_IT:
1643 		result = ModMessageHeuristicOrder::Samples;
1644 		break;
1645 	case MOD_TYPE_XM:
1646 		result = ModMessageHeuristicOrder::InstrumentsSamples;
1647 		break;
1648 	case MOD_TYPE_MDL:
1649 		result = ModMessageHeuristicOrder::InstrumentsSamples;
1650 		break;
1651 	case MOD_TYPE_IMF:
1652 		result = ModMessageHeuristicOrder::InstrumentsSamples;
1653 		break;
1654 	default:
1655 		result = ModMessageHeuristicOrder::Default;
1656 		break;
1657 	}
1658 	return result;
1659 }
1660 
1661 
1662 bool CSoundFile::SetTitle(const std::string &newTitle)
1663 {
1664 	if(m_songName != newTitle)
1665 	{
1666 		m_songName = newTitle;
1667 		return true;
1668 	}
1669 	return false;
1670 }
1671 
1672 
1673 double CSoundFile::GetPlaybackTimeAt(ORDERINDEX ord, ROWINDEX row, bool updateVars, bool updateSamplePos)
1674 {
1675 	const GetLengthType t = GetLength(updateVars ? (updateSamplePos ? eAdjustSamplePositions : eAdjust) : eNoAdjust, GetLengthTarget(ord, row)).back();
1676 	if(t.targetReached) return t.duration;
1677 	else return -1; //Given position not found from play sequence.
1678 }
1679 
1680 
1681 std::vector<SubSong> CSoundFile::GetAllSubSongs()
1682 {
1683 	std::vector<SubSong> subSongs;
1684 	for(SEQUENCEINDEX seq = 0; seq < Order.GetNumSequences(); seq++)
1685 	{
1686 		const auto subSongsSeq = GetLength(eNoAdjust, GetLengthTarget(true).StartPos(seq, 0, 0));
1687 		subSongs.reserve(subSongs.size() + subSongsSeq.size());
1688 		for(const auto &song : subSongsSeq)
1689 		{
1690 			subSongs.push_back({song.duration, song.startRow, song.endRow, song.lastRow, song.startOrder, song.endOrder, song.lastOrder, seq});
1691 		}
1692 	}
1693 	return subSongs;
1694 }
1695 
1696 
1697 // Calculate the length of a tick, depending on the tempo mode.
1698 // This differs from GetTickDuration() by not accumulating errors
1699 // because this is not called once per tick but in unrelated
1700 // circumstances. So this should not update error accumulation.
1701 void CSoundFile::RecalculateSamplesPerTick()
1702 {
1703 	switch(m_nTempoMode)
1704 	{
1705 	case TempoMode::Classic:
1706 	default:
1707 		m_PlayState.m_nSamplesPerTick = Util::muldiv(m_MixerSettings.gdwMixingFreq, 5 * TEMPO::fractFact, std::max(TEMPO::store_t(1), m_PlayState.m_nMusicTempo.GetRaw() << 1));
1708 		break;
1709 
1710 	case TempoMode::Modern:
1711 		m_PlayState.m_nSamplesPerTick = static_cast<uint32>((Util::mul32to64_unsigned(m_MixerSettings.gdwMixingFreq, 60 * TEMPO::fractFact) / std::max(uint64(1),  Util::mul32to64_unsigned(m_PlayState.m_nMusicSpeed, m_PlayState.m_nCurrentRowsPerBeat) * m_PlayState.m_nMusicTempo.GetRaw())));
1712 		break;
1713 
1714 	case TempoMode::Alternative:
1715 		m_PlayState.m_nSamplesPerTick = Util::muldiv(m_MixerSettings.gdwMixingFreq, TEMPO::fractFact, std::max(TEMPO::store_t(1), m_PlayState.m_nMusicTempo.GetRaw()));
1716 		break;
1717 	}
1718 #ifndef MODPLUG_TRACKER
1719 	m_PlayState.m_nSamplesPerTick = Util::muldivr(m_PlayState.m_nSamplesPerTick, m_nTempoFactor, 65536);
1720 #endif // !MODPLUG_TRACKER
1721 	if(!m_PlayState.m_nSamplesPerTick)
1722 		m_PlayState.m_nSamplesPerTick = 1;
1723 }
1724 
1725 
1726 // Get length of a tick in sample, with tick-to-tick tempo correction in modern tempo mode.
1727 // This has to be called exactly once per tick because otherwise the error accumulation
1728 // goes wrong.
1729 uint32 CSoundFile::GetTickDuration(PlayState &playState) const
1730 {
1731 	uint32 retval = 0;
1732 	switch(m_nTempoMode)
1733 	{
1734 	case TempoMode::Classic:
1735 	default:
1736 		retval = Util::muldiv(m_MixerSettings.gdwMixingFreq, 5 * TEMPO::fractFact, std::max(TEMPO::store_t(1), playState.m_nMusicTempo.GetRaw() << 1));
1737 		break;
1738 
1739 	case TempoMode::Alternative:
1740 		retval = Util::muldiv(m_MixerSettings.gdwMixingFreq, TEMPO::fractFact, std::max(TEMPO::store_t(1), playState.m_nMusicTempo.GetRaw()));
1741 		break;
1742 
1743 	case TempoMode::Modern:
1744 		{
1745 			double accurateBufferCount = static_cast<double>(m_MixerSettings.gdwMixingFreq) * (60.0 / (playState.m_nMusicTempo.ToDouble() * Util::mul32to64_unsigned(playState.m_nMusicSpeed, playState.m_nCurrentRowsPerBeat)));
1746 			const TempoSwing &swing = (Patterns.IsValidPat(playState.m_nPattern) && Patterns[playState.m_nPattern].HasTempoSwing())
1747 				? Patterns[playState.m_nPattern].GetTempoSwing()
1748 				: m_tempoSwing;
1749 			if(!swing.empty())
1750 			{
1751 				// Apply current row's tempo swing factor
1752 				TempoSwing::value_type swingFactor = swing[playState.m_nRow % swing.size()];
1753 				accurateBufferCount = accurateBufferCount * swingFactor / double(TempoSwing::Unity);
1754 			}
1755 			uint32 bufferCount = static_cast<int>(accurateBufferCount);
1756 			playState.m_dBufferDiff += accurateBufferCount - bufferCount;
1757 
1758 			//tick-to-tick tempo correction:
1759 			if(playState.m_dBufferDiff >= 1)
1760 			{
1761 				bufferCount++;
1762 				playState.m_dBufferDiff--;
1763 			} else if(m_PlayState.m_dBufferDiff <= -1)
1764 			{
1765 				bufferCount--;
1766 				playState.m_dBufferDiff++;
1767 			}
1768 			MPT_ASSERT(std::abs(playState.m_dBufferDiff) < 1.0);
1769 			retval = bufferCount;
1770 		}
1771 		break;
1772 	}
1773 #ifndef MODPLUG_TRACKER
1774 	// when the user modifies the tempo, we do not really care about accurate tempo error accumulation
1775 	retval = Util::muldivr_unsigned(retval, m_nTempoFactor, 65536);
1776 #endif // !MODPLUG_TRACKER
1777 	if(!retval)
1778 		retval  = 1;
1779 	return retval;
1780 }
1781 
1782 
1783 // Get the duration of a row in milliseconds, based on the current rows per beat and given speed and tempo settings.
1784 double CSoundFile::GetRowDuration(TEMPO tempo, uint32 speed) const
1785 {
1786 	switch(m_nTempoMode)
1787 	{
1788 	case TempoMode::Classic:
1789 	default:
1790 		return static_cast<double>(2500 * speed) / tempo.ToDouble();
1791 
1792 	case TempoMode::Modern:
1793 		{
1794 			// If there are any row delay effects, the row length factor compensates for those.
1795 			return 60000.0 / tempo.ToDouble() / static_cast<double>(m_PlayState.m_nCurrentRowsPerBeat);
1796 		}
1797 
1798 	case TempoMode::Alternative:
1799 		return static_cast<double>(1000 * speed) / tempo.ToDouble();
1800 	}
1801 }
1802 
1803 
1804 const CModSpecifications& CSoundFile::GetModSpecifications(const MODTYPE type)
1805 {
1806 	const CModSpecifications* p = nullptr;
1807 	SetModSpecsPointer(p, type);
1808 	return *p;
1809 }
1810 
1811 
1812 ChannelFlags CSoundFile::GetChannelMuteFlag()
1813 {
1814 #ifdef MODPLUG_TRACKER
1815 	return (TrackerSettings::Instance().m_dwPatternSetup & PATTERN_SYNCMUTE) ? CHN_SYNCMUTE : CHN_MUTE;
1816 #else
1817 	return CHN_SYNCMUTE;
1818 #endif
1819 }
1820 
1821 
1822 // Resolve note/instrument combination to real sample index. Return value is guaranteed to be in [0, GetNumSamples()].
1823 SAMPLEINDEX CSoundFile::GetSampleIndex(ModCommand::NOTE note, uint32 instr) const noexcept
1824 {
1825 	SAMPLEINDEX smp = 0;
1826 	if(GetNumInstruments())
1827 	{
1828 		if(ModCommand::IsNote(note) && instr <= GetNumInstruments() && Instruments[instr] != nullptr)
1829 			smp = Instruments[instr]->Keyboard[note - NOTE_MIN];
1830 	} else
1831 	{
1832 		smp = static_cast<SAMPLEINDEX>(instr);
1833 	}
1834 	if(smp <= GetNumSamples())
1835 		return smp;
1836 	else
1837 		return 0;
1838 }
1839 
1840 
1841 // Find an unused sample slot. If it is going to be assigned to an instrument, targetInstrument should be specified.
1842 // SAMPLEINDEX_INVLAID is returned if no free sample slot could be found.
1843 SAMPLEINDEX CSoundFile::GetNextFreeSample(INSTRUMENTINDEX targetInstrument, SAMPLEINDEX start) const
1844 {
1845 	// Find empty slot in two passes - in the first pass, we only search for samples with empty sample names,
1846 	// in the second pass we check all samples with non-empty sample names.
1847 	for(int passes = 0; passes < 2; passes++)
1848 	{
1849 		for(SAMPLEINDEX i = start; i <= GetModSpecifications().samplesMax; i++)
1850 		{
1851 			// Early exit for FM instruments
1852 			if(Samples[i].uFlags[CHN_ADLIB] && (targetInstrument == INSTRUMENTINDEX_INVALID || !IsSampleReferencedByInstrument(i, targetInstrument)))
1853 				continue;
1854 
1855 			// When loading into an instrument, ignore non-empty sample names. Else, only use this slot if the sample name is empty or we're in second pass.
1856 			if((i > GetNumSamples() && passes == 1)
1857 				|| (!Samples[i].HasSampleData() && (!m_szNames[i][0] || passes == 1 || targetInstrument != INSTRUMENTINDEX_INVALID))
1858 				|| (targetInstrument != INSTRUMENTINDEX_INVALID && IsSampleReferencedByInstrument(i, targetInstrument)))	// Not empty, but already used by this instrument. XXX this should only be done when replacing an instrument with a single sample! Otherwise it will use an inconsistent sample map!
1859 			{
1860 				// Empty slot, so it's a good candidate already.
1861 
1862 				// In instrument mode, check whether any instrument references this sample slot. If that is the case, we won't use it as it could lead to unwanted conflicts.
1863 				// If we are loading the sample *into* an instrument, we should also not consider that instrument's sample map, since it might be inconsistent at this time.
1864 				bool isReferenced = false;
1865 				for(INSTRUMENTINDEX ins = 1; ins <= GetNumInstruments(); ins++)
1866 				{
1867 					if(ins == targetInstrument)
1868 					{
1869 						continue;
1870 					}
1871 					if(IsSampleReferencedByInstrument(i, ins))
1872 					{
1873 						isReferenced = true;
1874 						break;
1875 					}
1876 				}
1877 				if(!isReferenced)
1878 				{
1879 					return i;
1880 				}
1881 			}
1882 		}
1883 	}
1884 
1885 	return SAMPLEINDEX_INVALID;
1886 }
1887 
1888 
1889 // Find an unused instrument slot.
1890 // INSTRUMENTINDEX_INVALID is returned if no free instrument slot could be found.
1891 INSTRUMENTINDEX CSoundFile::GetNextFreeInstrument(INSTRUMENTINDEX start) const
1892 {
1893 	for(INSTRUMENTINDEX i = start; i <= GetModSpecifications().instrumentsMax; i++)
1894 	{
1895 		if(Instruments[i] == nullptr)
1896 		{
1897 			return i;
1898 		}
1899 	}
1900 
1901 	return INSTRUMENTINDEX_INVALID;
1902 }
1903 
1904 
1905 // Check whether a given sample is used by a given instrument.
1906 bool CSoundFile::IsSampleReferencedByInstrument(SAMPLEINDEX sample, INSTRUMENTINDEX instr) const
1907 {
1908 	if(instr < 1 || instr > GetNumInstruments())
1909 		return false;
1910 
1911 	const ModInstrument *targetIns = Instruments[instr];
1912 	if(targetIns == nullptr)
1913 		return false;
1914 
1915 	return mpt::contains(mpt::as_span(targetIns->Keyboard).first(NOTE_MAX), sample);
1916 }
1917 
1918 
1919 ModInstrument *CSoundFile::AllocateInstrument(INSTRUMENTINDEX instr, SAMPLEINDEX assignedSample)
1920 {
1921 	if(instr == 0 || instr >= MAX_INSTRUMENTS)
1922 	{
1923 		return nullptr;
1924 	}
1925 
1926 	ModInstrument *ins = Instruments[instr];
1927 	if(ins != nullptr)
1928 	{
1929 		// Re-initialize instrument
1930 		*ins = ModInstrument(assignedSample);
1931 	} else
1932 	{
1933 		// Create new instrument
1934 		Instruments[instr] = ins = new (std::nothrow) ModInstrument(assignedSample);
1935 	}
1936 	if(ins != nullptr)
1937 	{
1938 		m_nInstruments = std::max(m_nInstruments, instr);
1939 	}
1940 	return ins;
1941 }
1942 
1943 
1944 void CSoundFile::PrecomputeSampleLoops(bool updateChannels)
1945 {
1946 	for(SAMPLEINDEX i = 1; i <= GetNumSamples(); i++)
1947 	{
1948 		Samples[i].PrecomputeLoops(*this, updateChannels);
1949 	}
1950 }
1951 
1952 
1953 #ifdef MPT_EXTERNAL_SAMPLES
1954 // Load external waveform, but keep sample properties like frequency, panning, etc...
1955 // Returns true if the file could be loaded.
1956 bool CSoundFile::LoadExternalSample(SAMPLEINDEX smp, const mpt::PathString &filename)
1957 {
1958 	bool ok = false;
1959 	InputFile f(filename, SettingCacheCompleteFileBeforeLoading());
1960 
1961 	if(f.IsValid())
1962 	{
1963 		const ModSample origSample = Samples[smp];
1964 		mpt::charbuf<MAX_SAMPLENAME> origName;
1965 		origName = m_szNames[smp];
1966 
1967 		FileReader file = GetFileReader(f);
1968 		ok = ReadSampleFromFile(smp, file, false);
1969 		if(ok)
1970 		{
1971 			// Copy over old attributes, but keep new sample data
1972 			ModSample &sample = GetSample(smp);
1973 			SmpLength newLength = sample.nLength;
1974 			void *newData = sample.samplev();
1975 			SampleFlags newFlags = sample.uFlags;
1976 
1977 			sample = origSample;
1978 			sample.nLength = newLength;
1979 			sample.pData.pSample = newData;
1980 			sample.uFlags.set(CHN_16BIT, newFlags[CHN_16BIT]);
1981 			sample.uFlags.set(CHN_STEREO, newFlags[CHN_STEREO]);
1982 			sample.uFlags.reset(SMP_MODIFIED);
1983 			sample.SanitizeLoops();
1984 		}
1985 		m_szNames[smp] = origName;
1986 	}
1987 	SetSamplePath(smp, filename);
1988 	return ok;
1989 }
1990 #endif // MPT_EXTERNAL_SAMPLES
1991 
1992 
1993 // Set up channel panning and volume suitable for MOD + similar files. If the current mod type is not MOD, bForceSetup has to be set to true.
1994 void CSoundFile::SetupMODPanning(bool bForceSetup)
1995 {
1996 	// Setup LRRL panning, max channel volume
1997 	if(!(GetType() & MOD_TYPE_MOD) && bForceSetup == false) return;
1998 
1999 	for(CHANNELINDEX nChn = 0; nChn < MAX_BASECHANNELS; nChn++)
2000 	{
2001 		ChnSettings[nChn].nVolume = 64;
2002 		ChnSettings[nChn].dwFlags.reset(CHN_SURROUND);
2003 		if(m_MixerSettings.MixerFlags & SNDMIX_MAXDEFAULTPAN)
2004 			ChnSettings[nChn].nPan = (((nChn & 3) == 1) || ((nChn & 3) == 2)) ? 256 : 0;
2005 		else
2006 			ChnSettings[nChn].nPan = (((nChn & 3) == 1) || ((nChn & 3) == 2)) ? 0xC0 : 0x40;
2007 	}
2008 }
2009 
2010 
2011 void CSoundFile::PropagateXMAutoVibrato(INSTRUMENTINDEX ins, VibratoType type, uint8 sweep, uint8 depth, uint8 rate)
2012 {
2013 	if(ins > m_nInstruments || Instruments[ins] == nullptr)
2014 		return;
2015 	const std::set<SAMPLEINDEX> referencedSamples = Instruments[ins]->GetSamples();
2016 
2017 	// Propagate changes to all samples that belong to this instrument.
2018 	for(auto sample : referencedSamples)
2019 	{
2020 		if(sample <= m_nSamples)
2021 		{
2022 			Samples[sample].nVibDepth = depth;
2023 			Samples[sample].nVibType = type;
2024 			Samples[sample].nVibRate = rate;
2025 			Samples[sample].nVibSweep = sweep;
2026 		}
2027 	}
2028 }
2029 
2030 
2031 // Normalize the tempo swing coefficients so that they add up to exactly the specified tempo again
2032 void TempoSwing::Normalize()
2033 {
2034 	if(empty()) return;
2035 	uint64 sum = 0;
2036 	for(auto &i : *this)
2037 	{
2038 		Limit(i, Unity / 4u, Unity * 4u);
2039 		sum += i;
2040 	}
2041 	sum /= size();
2042 	int64 remain = Unity * size();
2043 	for(auto &i : *this)
2044 	{
2045 		i = Util::muldivr_unsigned(i, Unity, static_cast<int32>(sum));
2046 		remain -= i;
2047 	}
2048 	//MPT_ASSERT(static_cast<uint32>(std::abs(static_cast<int32>(remain))) <= size());
2049 	at(0) += static_cast<int32>(remain);
2050 }
2051 
2052 
2053 void TempoSwing::Serialize(std::ostream &oStrm, const TempoSwing &swing)
2054 {
2055 	mpt::IO::WriteIntLE<uint16>(oStrm, static_cast<uint16>(swing.size()));
2056 	for(std::size_t i = 0; i < swing.size(); i++)
2057 	{
2058 		mpt::IO::WriteIntLE<uint32>(oStrm, swing[i]);
2059 	}
2060 }
2061 
2062 
2063 void TempoSwing::Deserialize(std::istream &iStrm, TempoSwing &swing, const size_t)
2064 {
2065 	uint16 numEntries;
2066 	mpt::IO::ReadIntLE<uint16>(iStrm, numEntries);
2067 	swing.resize(numEntries);
2068 	for(uint16 i = 0; i < numEntries; i++)
2069 	{
2070 		mpt::IO::ReadIntLE<uint32>(iStrm, swing[i]);
2071 	}
2072 	swing.Normalize();
2073 }
2074 
2075 
2076 OPENMPT_NAMESPACE_END
2077