1 /*
2  * Load_mod.cpp
3  * ------------
4  * Purpose: MOD / NST (ProTracker / NoiseTracker), M15 / STK (Ultimate Soundtracker / Soundtracker) and ST26 (SoundTracker 2.6 / Ice Tracker) module loader / saver
5  * Notes  : "2000 LOC for processing MOD files?!" you say? Well, this file also contains loaders for some formats that are almost identical to MOD, and extensive
6  *          heuristics for more or less broken MOD files and files saved with tons of different trackers, to allow for the most optimal playback.
7  * Authors: Olivier Lapicque
8  *          OpenMPT Devs
9  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
10  */
11 
12 
13 #include "stdafx.h"
14 #include "Loaders.h"
15 #include "Tables.h"
16 #ifndef MODPLUG_NO_FILESAVE
17 #include "mpt/io/base.hpp"
18 #include "mpt/io/io.hpp"
19 #include "mpt/io/io_stdstream.hpp"
20 #include "../common/mptFileIO.h"
21 #endif
22 #ifdef MPT_EXTERNAL_SAMPLES
23 // For loading external data in Startrekker files
24 #include "../common/mptPathString.h"
25 #endif  // MPT_EXTERNAL_SAMPLES
26 
27 OPENMPT_NAMESPACE_BEGIN
28 
ConvertModCommand(ModCommand & m)29 void CSoundFile::ConvertModCommand(ModCommand &m)
30 {
31 	switch(m.command)
32 	{
33 	case 0x00:	if(m.param) m.command = CMD_ARPEGGIO; break;
34 	case 0x01:	m.command = CMD_PORTAMENTOUP; break;
35 	case 0x02:	m.command = CMD_PORTAMENTODOWN; break;
36 	case 0x03:	m.command = CMD_TONEPORTAMENTO; break;
37 	case 0x04:	m.command = CMD_VIBRATO; break;
38 	case 0x05:	m.command = CMD_TONEPORTAVOL; break;
39 	case 0x06:	m.command = CMD_VIBRATOVOL; break;
40 	case 0x07:	m.command = CMD_TREMOLO; break;
41 	case 0x08:	m.command = CMD_PANNING8; break;
42 	case 0x09:	m.command = CMD_OFFSET; break;
43 	case 0x0A:	m.command = CMD_VOLUMESLIDE; break;
44 	case 0x0B:	m.command = CMD_POSITIONJUMP; break;
45 	case 0x0C:	m.command = CMD_VOLUME; break;
46 	case 0x0D:	m.command = CMD_PATTERNBREAK; m.param = ((m.param >> 4) * 10) + (m.param & 0x0F); break;
47 	case 0x0E:	m.command = CMD_MODCMDEX; break;
48 	case 0x0F:
49 		// For a very long time, this code imported 0x20 as CMD_SPEED for MOD files, but this seems to contradict
50 		// pretty much the majority of other MOD player out there.
51 		// 0x20 is Speed: Impulse Tracker, Scream Tracker, old ModPlug
52 		// 0x20 is Tempo: ProTracker, XMPlay, Imago Orpheus, Cubic Player, ChibiTracker, BeRoTracker, DigiTrakker, DigiTrekker, Disorder Tracker 2, DMP, Extreme's Tracker, ...
53 		if(m.param < 0x20)
54 			m.command = CMD_SPEED;
55 		else
56 			m.command = CMD_TEMPO;
57 		break;
58 
59 	// Extension for XM extended effects
60 	case 'G' - 55:	m.command = CMD_GLOBALVOLUME; break;  //16
61 	case 'H' - 55:	m.command = CMD_GLOBALVOLSLIDE; break;
62 	case 'K' - 55:	m.command = CMD_KEYOFF; break;
63 	case 'L' - 55:	m.command = CMD_SETENVPOSITION; break;
64 	case 'P' - 55:	m.command = CMD_PANNINGSLIDE; break;
65 	case 'R' - 55:	m.command = CMD_RETRIG; break;
66 	case 'T' - 55:	m.command = CMD_TREMOR; break;
67 	case 'W' - 55:	m.command = CMD_DUMMY; break;
68 	case 'X' - 55:	m.command = CMD_XFINEPORTAUPDOWN;	break;
69 	case 'Y' - 55:	m.command = CMD_PANBRELLO; break;   // 34
70 	case 'Z' - 55:	m.command = CMD_MIDI; break;        // 35
71 	case '\\' - 56:	m.command = CMD_SMOOTHMIDI; break;  // 36 - note: this is actually displayed as "-" in FT2, but seems to be doing nothing.
72 	case 37:		m.command = CMD_SMOOTHMIDI; break;  // BeRoTracker uses this for smooth MIDI macros for some reason; in old OpenMPT versions this was reserved for the unimplemented "velocity" command
73 	case '#' + 3:	m.command = CMD_XPARAM; break;      // 38
74 	default:		m.command = CMD_NONE;
75 	}
76 }
77 
78 #ifndef MODPLUG_NO_FILESAVE
79 
ModSaveCommand(uint8 & command,uint8 & param,bool toXM,bool compatibilityExport) const80 void CSoundFile::ModSaveCommand(uint8 &command, uint8 &param, bool toXM, bool compatibilityExport) const
81 {
82 	switch(command)
83 	{
84 	case CMD_NONE:		command = param = 0; break;
85 	case CMD_ARPEGGIO:	command = 0; break;
86 	case CMD_PORTAMENTOUP:
87 		if (GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM|MOD_TYPE_MPT))
88 		{
89 			if ((param & 0xF0) == 0xE0) { command = 0x0E; param = ((param & 0x0F) >> 2) | 0x10; break; }
90 			else if ((param & 0xF0) == 0xF0) { command = 0x0E; param &= 0x0F; param |= 0x10; break; }
91 		}
92 		command = 0x01;
93 		break;
94 	case CMD_PORTAMENTODOWN:
95 		if(GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM|MOD_TYPE_MPT))
96 		{
97 			if ((param & 0xF0) == 0xE0) { command = 0x0E; param= ((param & 0x0F) >> 2) | 0x20; break; }
98 			else if ((param & 0xF0) == 0xF0) { command = 0x0E; param &= 0x0F; param |= 0x20; break; }
99 		}
100 		command = 0x02;
101 		break;
102 	case CMD_TONEPORTAMENTO:	command = 0x03; break;
103 	case CMD_VIBRATO:			command = 0x04; break;
104 	case CMD_TONEPORTAVOL:		command = 0x05; break;
105 	case CMD_VIBRATOVOL:		command = 0x06; break;
106 	case CMD_TREMOLO:			command = 0x07; break;
107 	case CMD_PANNING8:
108 		command = 0x08;
109 		if(GetType() & MOD_TYPE_S3M)
110 		{
111 			if(param <= 0x80)
112 			{
113 				param = mpt::saturate_cast<uint8>(param * 2);
114 			}
115 			else if(param == 0xA4)	// surround
116 			{
117 				if(compatibilityExport || !toXM)
118 				{
119 					command = param = 0;
120 				}
121 				else
122 				{
123 					command = 'X' - 55;
124 					param = 91;
125 				}
126 			}
127 		}
128 		break;
129 	case CMD_OFFSET:			command = 0x09; break;
130 	case CMD_VOLUMESLIDE:		command = 0x0A; break;
131 	case CMD_POSITIONJUMP:		command = 0x0B; break;
132 	case CMD_VOLUME:			command = 0x0C; break;
133 	case CMD_PATTERNBREAK:		command = 0x0D; param = ((param / 10) << 4) | (param % 10); break;
134 	case CMD_MODCMDEX:			command = 0x0E; break;
135 	case CMD_SPEED:				command = 0x0F; param = std::min(param, uint8(0x1F)); break;
136 	case CMD_TEMPO:				command = 0x0F; param = std::max(param, uint8(0x20)); break;
137 	case CMD_GLOBALVOLUME:		command = 'G' - 55; break;
138 	case CMD_GLOBALVOLSLIDE:	command = 'H' - 55; break;
139 	case CMD_KEYOFF:			command = 'K' - 55; break;
140 	case CMD_SETENVPOSITION:	command = 'L' - 55; break;
141 	case CMD_PANNINGSLIDE:		command = 'P' - 55; break;
142 	case CMD_RETRIG:			command = 'R' - 55; break;
143 	case CMD_TREMOR:			command = 'T' - 55; break;
144 	case CMD_DUMMY:				command = 'W' - 55; break;
145 	case CMD_XFINEPORTAUPDOWN:	command = 'X' - 55;
146 		if(compatibilityExport && param >= 0x30)	// X1x and X2x are legit, everything above are MPT extensions, which don't belong here.
147 			param = 0;	// Don't set command to 0 to indicate that there *was* some X command here...
148 		break;
149 	case CMD_PANBRELLO:
150 		if(compatibilityExport)
151 			command = param = 0;
152 		else
153 			command = 'Y' - 55;
154 		break;
155 	case CMD_MIDI:
156 		if(compatibilityExport)
157 			command = param = 0;
158 		else
159 			command = 'Z' - 55;
160 		break;
161 	case CMD_SMOOTHMIDI: //rewbs.smoothVST: 36
162 		if(compatibilityExport)
163 			command = param = 0;
164 		else
165 			command = '\\' - 56;
166 		break;
167 	case CMD_XPARAM: //rewbs.XMfixes - XParam is 38
168 		if(compatibilityExport)
169 			command = param = 0;
170 		else
171 			command = '#' + 3;
172 		break;
173 	case CMD_S3MCMDEX:
174 		switch(param & 0xF0)
175 		{
176 		case 0x10:	command = 0x0E; param = (param & 0x0F) | 0x30; break;
177 		case 0x20:	command = 0x0E; param = (param & 0x0F) | 0x50; break;
178 		case 0x30:	command = 0x0E; param = (param & 0x0F) | 0x40; break;
179 		case 0x40:	command = 0x0E; param = (param & 0x0F) | 0x70; break;
180 		case 0x90:
181 			if(compatibilityExport)
182 				command = param = 0;
183 			else
184 				command = 'X' - 55;
185 			break;
186 		case 0xB0:	command = 0x0E; param = (param & 0x0F) | 0x60; break;
187 		case 0xA0:
188 		case 0x50:
189 		case 0x70:
190 		case 0x60:	command = param = 0; break;
191 		default:	command = 0x0E; break;
192 		}
193 		break;
194 	default:
195 		command = param = 0;
196 	}
197 
198 	// Don't even think about saving XM effects in MODs...
199 	if(command > 0x0F && !toXM)
200 	{
201 		command = param = 0;
202 	}
203 }
204 
205 #endif  // MODPLUG_NO_FILESAVE
206 
207 
208 // File Header
209 struct MODFileHeader
210 {
211 	uint8be numOrders;
212 	uint8be restartPos;
213 	uint8be orderList[128];
214 };
215 
216 MPT_BINARY_STRUCT(MODFileHeader, 130)
217 
218 
219 // Sample Header
220 struct MODSampleHeader
221 {
222 	char     name[22];
223 	uint16be length;
224 	uint8be  finetune;
225 	uint8be  volume;
226 	uint16be loopStart;
227 	uint16be loopLength;
228 
229 	// Convert an MOD sample header to OpenMPT's internal sample header.
ConvertToMPTMODSampleHeader230 	void ConvertToMPT(ModSample &mptSmp, bool is4Chn) const
231 	{
232 		mptSmp.Initialize(MOD_TYPE_MOD);
233 		mptSmp.nLength = length * 2;
234 		mptSmp.nFineTune = MOD2XMFineTune(finetune & 0x0F);
235 		mptSmp.nVolume = 4u * std::min(volume.get(), uint8(64));
236 
237 		SmpLength lStart = loopStart * 2;
238 		SmpLength lLength = loopLength * 2;
239 		// See if loop start is incorrect as words, but correct as bytes (like in Soundtracker modules)
240 		if(lLength > 2 && (lStart + lLength > mptSmp.nLength)
241 		   && (lStart / 2 + lLength <= mptSmp.nLength))
242 		{
243 			lStart /= 2;
244 		}
245 
246 		if(mptSmp.nLength == 2)
247 		{
248 			mptSmp.nLength = 0;
249 		}
250 
251 		if(mptSmp.nLength)
252 		{
253 			mptSmp.nLoopStart = lStart;
254 			mptSmp.nLoopEnd = lStart + lLength;
255 
256 			if(mptSmp.nLoopStart >= mptSmp.nLength)
257 			{
258 				mptSmp.nLoopStart = mptSmp.nLength - 1;
259 			}
260 			if(mptSmp.nLoopStart > mptSmp.nLoopEnd || mptSmp.nLoopEnd < 4 || mptSmp.nLoopEnd - mptSmp.nLoopStart < 4)
261 			{
262 				mptSmp.nLoopStart = 0;
263 				mptSmp.nLoopEnd = 0;
264 			}
265 
266 			// Fix for most likely broken sample loops. This fixes super_sufm_-_new_life.mod (M.K.) which has a long sample which is looped from 0 to 4.
267 			// This module also has notes outside of the Amiga frequency range, so we cannot say that it should be played using ProTracker one-shot loops.
268 			// On the other hand, "Crew Generation" by Necros (6CHN) has a sample with a similar loop, which is supposed to be played.
269 			// To be able to correctly play both modules, we will draw a somewhat arbitrary line here and trust the loop points in MODs with more than
270 			// 4 channels, even if they are tiny and at the very beginning of the sample.
271 			if(mptSmp.nLoopEnd <= 8 && mptSmp.nLoopStart == 0 && mptSmp.nLength > mptSmp.nLoopEnd && is4Chn)
272 			{
273 				mptSmp.nLoopEnd = 0;
274 			}
275 			if(mptSmp.nLoopEnd > mptSmp.nLoopStart)
276 			{
277 				mptSmp.uFlags.set(CHN_LOOP);
278 			}
279 		}
280 	}
281 
282 	// Convert OpenMPT's internal sample header to a MOD sample header.
ConvertToMODMODSampleHeader283 	SmpLength ConvertToMOD(const ModSample &mptSmp)
284 	{
285 		SmpLength writeLength = mptSmp.HasSampleData() ? mptSmp.nLength : 0;
286 		// If the sample size is odd, we have to add a padding byte, as all sample sizes in MODs are even.
287 		if((writeLength % 2u) != 0)
288 		{
289 			writeLength++;
290 		}
291 		LimitMax(writeLength, SmpLength(0x1FFFE));
292 
293 		length = static_cast<uint16>(writeLength / 2u);
294 
295 		if(mptSmp.RelativeTone < 0)
296 		{
297 			finetune = 0x08;
298 		} else if(mptSmp.RelativeTone > 0)
299 		{
300 			finetune = 0x07;
301 		} else
302 		{
303 			finetune = XM2MODFineTune(mptSmp.nFineTune);
304 		}
305 		volume = static_cast<uint8>(mptSmp.nVolume / 4u);
306 
307 		loopStart = 0;
308 		loopLength = 1;
309 		if(mptSmp.uFlags[CHN_LOOP] && (mptSmp.nLoopStart + 2u) < writeLength)
310 		{
311 			const SmpLength loopEnd = Clamp(mptSmp.nLoopEnd, (mptSmp.nLoopStart & ~1) + 2u, writeLength) & ~1;
312 			loopStart = static_cast<uint16>(mptSmp.nLoopStart / 2u);
313 			loopLength = static_cast<uint16>((loopEnd - (mptSmp.nLoopStart & ~1)) / 2u);
314 		}
315 
316 		return writeLength;
317 	}
318 
319 	// Compute a "rating" of this sample header by counting invalid header data to ultimately reject garbage files.
GetInvalidByteScoreMODSampleHeader320 	uint32 GetInvalidByteScore() const
321 	{
322 		return ((volume > 64) ? 1 : 0)
323 		       + ((finetune > 15) ? 1 : 0)
324 		       + ((loopStart > length * 2) ? 1 : 0);
325 	}
326 
327 	// Suggested threshold for rejecting invalid files based on cumulated score returned by GetInvalidByteScore
328 	static constexpr uint32 INVALID_BYTE_THRESHOLD = 40;
329 
330 	// This threshold is used for files where the file magic only gives a
331 	// fragile result which alone would lead to too many false positives.
332 	// In particular, the files from Inconexia demo by Iguana
333 	// (https://www.pouet.net/prod.php?which=830) which have 3 \0 bytes in
334 	// the file magic tend to cause misdetection of random files.
335 	static constexpr uint32 INVALID_BYTE_FRAGILE_THRESHOLD = 1;
336 
337 	// Retrieve the internal sample format flags for this sample.
GetSampleFormatMODSampleHeader338 	static SampleIO GetSampleFormat()
339 	{
340 		return SampleIO(
341 			SampleIO::_8bit,
342 			SampleIO::mono,
343 			SampleIO::bigEndian,
344 			SampleIO::signedPCM);
345 	}
346 };
347 
348 MPT_BINARY_STRUCT(MODSampleHeader, 30)
349 
350 // Pattern data of a 4-channel MOD file
351 using MODPatternData = std::array<std::array<std::array<uint8, 4>, 4>, 64>;
352 
353 // Synthesized StarTrekker instruments
354 struct AMInstrument
355 {
356 	char     am[2];        // "AM"
357 	char     zero[4];
358 	uint16be startLevel;   // Start level
359 	uint16be attack1Level; // Attack 1 level
360 	uint16be attack1Speed; // Attack 1 speed
361 	uint16be attack2Level; // Attack 2 level
362 	uint16be attack2Speed; // Attack 2 speed
363 	uint16be sustainLevel; // Sustain level
364 	uint16be decaySpeed;   // Decay speed
365 	uint16be sustainTime;  // Sustain time
366 	uint16be nt;           // ?
367 	uint16be releaseSpeed; // Release speed
368 	uint16be waveform;     // Waveform
369 	int16be  pitchFall;    // Pitch fall
370 	uint16be vibAmp;       // Vibrato amplitude
371 	uint16be vibSpeed;     // Vibrato speed
372 	uint16be octave;       // Base frequency
373 
ConvertToMPTAMInstrument374 	void ConvertToMPT(ModSample &sample, ModInstrument &ins, mpt::fast_prng &rng) const
375 	{
376 		sample.nLength = waveform == 3 ? 1024 : 32;
377 		sample.nLoopStart = 0;
378 		sample.nLoopEnd = sample.nLength;
379 		sample.uFlags.set(CHN_LOOP);
380 		sample.nVolume = 256;  // prelude.mod has volume 0 in sample header
381 		sample.nVibDepth = mpt::saturate_cast<uint8>(vibAmp * 2);
382 		sample.nVibRate = static_cast<uint8>(vibSpeed);
383 		sample.nVibType = VIB_SINE;
384 		sample.RelativeTone = static_cast<int8>(-12 * octave);
385 		if(sample.AllocateSample())
386 		{
387 			int8 *p = sample.sample8();
388 			for(SmpLength i = 0; i < sample.nLength; i++)
389 			{
390 				switch(waveform)
391 				{
392 				default:
393 				case 0: p[i] = ModSinusTable[i * 2];            break; // Sine
394 				case 1: p[i] = static_cast<int8>(-128 + i * 8); break; // Saw
395 				case 2: p[i] = i < 16 ? -128 : 127;             break; // Square
396 				case 3: p[i] = mpt::random<int8>(rng);          break; // Noise
397 				}
398 			}
399 		}
400 
401 		InstrumentEnvelope &volEnv = ins.VolEnv;
402 		volEnv.dwFlags.set(ENV_ENABLED);
403 		volEnv.reserve(6);
404 		volEnv.push_back(0, static_cast<EnvelopeNode::value_t>(startLevel / 4));
405 
406 		const struct
407 		{
408 			uint16 level, speed;
409 		} points[] = {{startLevel, 0}, {attack1Level, attack1Speed}, {attack2Level, attack2Speed}, {sustainLevel, decaySpeed}, {sustainLevel, sustainTime}, {0, releaseSpeed}};
410 
411 		for(uint8 i = 1; i < std::size(points); i++)
412 		{
413 			int duration = std::min(points[i].speed, uint16(256));
414 			// Sustain time is already in ticks, no need to compute the segment duration.
415 			if(i != 4)
416 			{
417 				if(duration == 0)
418 				{
419 					volEnv.dwFlags.set(ENV_LOOP);
420 					volEnv.nLoopStart = volEnv.nLoopEnd = static_cast<uint8>(volEnv.size() - 1);
421 					break;
422 				}
423 
424 				// Startrekker increments / decrements the envelope level by the stage speed
425 				// until it reaches the next stage level.
426 				int a, b;
427 				if(points[i].level > points[i - 1].level)
428 				{
429 					a = points[i].level - points[i - 1].level;
430 					b = 256 - points[i - 1].level;
431 				} else
432 				{
433 					a = points[i - 1].level - points[i].level;
434 					b = points[i - 1].level;
435 				}
436 				// Release time is again special.
437 				if(i == 5)
438 					b = 256;
439 				else if(b == 0)
440 					b = 1;
441 				duration = std::max((256 * a) / (duration * b), 1);
442 			}
443 			if(duration > 0)
444 			{
445 				volEnv.push_back(volEnv.back().tick + static_cast<EnvelopeNode::tick_t>(duration), static_cast<EnvelopeNode::value_t>(points[i].level / 4));
446 			}
447 		}
448 
449 		if(pitchFall)
450 		{
451 			InstrumentEnvelope &pitchEnv = ins.PitchEnv;
452 			pitchEnv.dwFlags.set(ENV_ENABLED);
453 			pitchEnv.reserve(2);
454 			pitchEnv.push_back(0, ENVELOPE_MID);
455 			// cppcheck false-positive
456 			// cppcheck-suppress zerodiv
457 			pitchEnv.push_back(static_cast<EnvelopeNode::tick_t>(1024 / abs(pitchFall)), pitchFall > 0 ? ENVELOPE_MIN : ENVELOPE_MAX);
458 		}
459 	}
460 };
461 
462 MPT_BINARY_STRUCT(AMInstrument, 36)
463 
464 struct PT36IffChunk
465 {
466 	// IFF chunk names
467 	enum ChunkIdentifiers
468 	{
469 		idVERS = MagicBE("VERS"),
470 		idINFO = MagicBE("INFO"),
471 		idCMNT = MagicBE("CMNT"),
472 		idPTDT = MagicBE("PTDT"),
473 	};
474 
475 	uint32be signature;  // IFF chunk name
476 	uint32be chunksize;  // chunk size without header
477 };
478 
479 MPT_BINARY_STRUCT(PT36IffChunk, 8)
480 
481 struct PT36InfoChunk
482 {
483 	char     name[32];
484 	uint16be numSamples;
485 	uint16be numOrders;
486 	uint16be numPatterns;
487 	uint16be volume;
488 	uint16be tempo;
489 	uint16be flags;
490 	uint16be dateDay;
491 	uint16be dateMonth;
492 	uint16be dateYear;
493 	uint16be dateHour;
494 	uint16be dateMinute;
495 	uint16be dateSecond;
496 	uint16be playtimeHour;
497 	uint16be playtimeMinute;
498 	uint16be playtimeSecond;
499 	uint16be playtimeMsecond;
500 };
501 
502 MPT_BINARY_STRUCT(PT36InfoChunk, 64)
503 
504 
505 // Check if header magic equals a given string.
IsMagic(const char * magic1,const char (& magic2)[5])506 static bool IsMagic(const char *magic1, const char (&magic2)[5])
507 {
508 	return std::memcmp(magic1, magic2, 4) == 0;
509 }
510 
511 
ReadSample(FileReader & file,MODSampleHeader & sampleHeader,ModSample & sample,mpt::charbuf<MAX_SAMPLENAME> & sampleName,bool is4Chn)512 static uint32 ReadSample(FileReader &file, MODSampleHeader &sampleHeader, ModSample &sample, mpt::charbuf<MAX_SAMPLENAME> &sampleName, bool is4Chn)
513 {
514 	file.ReadStruct(sampleHeader);
515 	sampleHeader.ConvertToMPT(sample, is4Chn);
516 
517 	sampleName = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name);
518 	// Get rid of weird characters in sample names.
519 	for(auto &c : sampleName.buf)
520 	{
521 		if(c > 0 && c < ' ')
522 		{
523 			c = ' ';
524 		}
525 	}
526 	// Check for invalid values
527 	return sampleHeader.GetInvalidByteScore();
528 }
529 
530 
531 // Count malformed bytes in MOD pattern data
CountMalformedMODPatternData(const MODPatternData & patternData,const bool allow31Samples)532 static uint32 CountMalformedMODPatternData(const MODPatternData &patternData, const bool allow31Samples)
533 {
534 	const uint8 mask = allow31Samples ? 0xE0 : 0xF0;
535 	uint32 malformedBytes = 0;
536 	for(const auto &row : patternData)
537 	{
538 		for(const auto &data : row)
539 		{
540 			if(data[0] & mask)
541 				malformedBytes++;
542 		}
543 	}
544 	return malformedBytes;
545 }
546 
547 
548 // Check if number of malformed bytes in MOD pattern data exceeds some threshold
549 template <typename TFileReader>
ValidateMODPatternData(TFileReader & file,const uint32 threshold,const bool allow31Samples)550 static bool ValidateMODPatternData(TFileReader &file, const uint32 threshold, const bool allow31Samples)
551 {
552 	MODPatternData patternData;
553 	if(!file.Read(patternData))
554 		return false;
555 	return CountMalformedMODPatternData(patternData, allow31Samples) <= threshold;
556 }
557 
558 
559 // Parse the order list to determine how many patterns are used in the file.
GetNumPatterns(FileReader & file,ModSequence & Order,ORDERINDEX numOrders,SmpLength totalSampleLen,CHANNELINDEX & numChannels,SmpLength wowSampleLen,bool validateHiddenPatterns)560 static PATTERNINDEX GetNumPatterns(FileReader &file, ModSequence &Order, ORDERINDEX numOrders, SmpLength totalSampleLen, CHANNELINDEX &numChannels, SmpLength wowSampleLen, bool validateHiddenPatterns)
561 {
562 	PATTERNINDEX numPatterns = 0;         // Total number of patterns in file (determined by going through the whole order list) with pattern number < 128
563 	PATTERNINDEX officialPatterns = 0;    // Number of patterns only found in the "official" part of the order list (i.e. order positions < claimed order length)
564 	PATTERNINDEX numPatternsIllegal = 0;  // Total number of patterns in file, also counting in "invalid" pattern indexes >= 128
565 
566 	for(ORDERINDEX ord = 0; ord < 128; ord++)
567 	{
568 		PATTERNINDEX pat = Order[ord];
569 		if(pat < 128 && numPatterns <= pat)
570 		{
571 			numPatterns = pat + 1;
572 			if(ord < numOrders)
573 			{
574 				officialPatterns = numPatterns;
575 			}
576 		}
577 		if(pat >= numPatternsIllegal)
578 		{
579 			numPatternsIllegal = pat + 1;
580 		}
581 	}
582 
583 	// Remove the garbage patterns past the official order end now that we don't need them anymore.
584 	Order.resize(numOrders);
585 
586 	const size_t patternStartOffset = file.GetPosition();
587 	const size_t sizeWithoutPatterns = totalSampleLen + patternStartOffset;
588 
589 	if(wowSampleLen && (wowSampleLen + patternStartOffset) + numPatterns * 8 * 256 == (file.GetLength() & ~1))
590 	{
591 		// Check if this is a Mod's Grave WOW file... WOW files use the M.K. magic but are actually 8CHN files.
592 		// We do a simple pattern validation as well for regular MOD files that have non-module data attached at the end
593 		// (e.g. ponylips.mod, MD5 c039af363b1d99a492dafc5b5f9dd949, SHA1 1bee1941c47bc6f913735ce0cf1880b248b8fc93)
594 		file.Seek(patternStartOffset + numPatterns * 4 * 256);
595 		if(ValidateMODPatternData(file, 16, true))
596 			numChannels = 8;
597 		file.Seek(patternStartOffset);
598 	} else if(numPatterns != officialPatterns && validateHiddenPatterns)
599 	{
600 		// Fix SoundTracker modules where "hidden" patterns should be ignored.
601 		// razor-1911.mod (MD5 b75f0f471b0ae400185585ca05bf7fe8, SHA1 4de31af234229faec00f1e85e1e8f78f405d454b)
602 		// and captain_fizz.mod (MD5 55bd89fe5a8e345df65438dbfc2df94e, SHA1 9e0e8b7dc67939885435ea8d3ff4be7704207a43)
603 		// seem to have the "correct" file size when only taking the "official" patterns into account,
604 		// but they only play correctly when also loading the inofficial patterns.
605 		// On the other hand, the SoundTracker module
606 		// wolf1.mod (MD5 a4983d7a432d324ce8261b019257f4ed, SHA1 aa6b399d02546bcb6baf9ec56a8081730dea3f44),
607 		// wolf3.mod (MD5 af60840815aa9eef43820a7a04417fa6, SHA1 24d6c2e38894f78f6c5c6a4b693a016af8fa037b)
608 		// and jean_baudlot_-_bad_dudes_vs_dragonninja-dragonf.mod (MD5 fa48e0f805b36bdc1833f6b82d22d936, SHA1 39f2f8319f4847fe928b9d88eee19d79310b9f91)
609 		// only play correctly if we ignore the hidden patterns.
610 		// Hence, we have a peek at the first hidden pattern and check if it contains a lot of illegal data.
611 		// If that is the case, we assume it's part of the sample data and only consider the "official" patterns.
612 		file.Seek(patternStartOffset + officialPatterns * 1024);
613 		if(!ValidateMODPatternData(file, 64, true))
614 			numPatterns = officialPatterns;
615 		file.Seek(patternStartOffset);
616 	}
617 
618 #ifdef MPT_BUILD_DEBUG
619 	// Check if the "hidden" patterns in the order list are actually real, i.e. if they are saved in the file.
620 	// OpenMPT did this check in the past, but no other tracker appears to do this.
621 	// Interestingly, (broken) variants of the ProTracker modules
622 	// "killing butterfly" (MD5 bd676358b1dbb40d40f25435e845cf6b, SHA1 9df4ae21214ff753802756b616a0cafaeced8021),
623 	// "quartex" by Reflex (MD5 35526bef0fb21cb96394838d94c14bab, SHA1 116756c68c7b6598dcfbad75a043477fcc54c96c),
624 	// seem to have the "correct" file size when only taking the "official" patterns into account, but they only play
625 	// correctly when also loading the inofficial patterns.
626 	// See also the above check for ambiguities with SoundTracker modules.
627 	// Keep this assertion in the code to find potential other broken MODs.
628 	if(numPatterns != officialPatterns && sizeWithoutPatterns + officialPatterns * numChannels * 256 == file.GetLength())
629 	{
630 		MPT_ASSERT(false);
631 		//numPatterns = officialPatterns;
632 	} else
633 #endif
634 	if(numPatternsIllegal > numPatterns && sizeWithoutPatterns + numPatternsIllegal * numChannels * 256 == file.GetLength())
635 	{
636 		// Even those illegal pattern indexes (> 128) appear to be valid... What a weird file!
637 		// e.g. NIETNU.MOD, where the end of the order list is filled with FF rather than 00, and the file actually contains 256 patterns.
638 		numPatterns = numPatternsIllegal;
639 	} else if(numPatternsIllegal >= 0xFF)
640 	{
641 		// Patterns FE and FF are used with S3M semantics (e.g. some MODs written with old OpenMPT versions)
642 		Order.Replace(0xFE, Order.GetIgnoreIndex());
643 		Order.Replace(0xFF, Order.GetInvalidPatIndex());
644 	}
645 
646 	return numPatterns;
647 }
648 
649 
ReadMODPatternEntry(FileReader & file,ModCommand & m)650 void CSoundFile::ReadMODPatternEntry(FileReader &file, ModCommand &m)
651 {
652 	ReadMODPatternEntry(file.ReadArray<uint8, 4>(), m);
653 }
654 
655 
ReadMODPatternEntry(const std::array<uint8,4> data,ModCommand & m)656 void CSoundFile::ReadMODPatternEntry(const std::array<uint8, 4> data, ModCommand &m)
657 {
658 	// Read Period
659 	uint16 period = (((static_cast<uint16>(data[0]) & 0x0F) << 8) | data[1]);
660 	size_t note = NOTE_NONE;
661 	if(period > 0 && period != 0xFFF)
662 	{
663 		note = std::size(ProTrackerPeriodTable) + 23 + NOTE_MIN;
664 		for(size_t i = 0; i < std::size(ProTrackerPeriodTable); i++)
665 		{
666 			if(period >= ProTrackerPeriodTable[i])
667 			{
668 				if(period != ProTrackerPeriodTable[i] && i != 0)
669 				{
670 					uint16 p1 = ProTrackerPeriodTable[i - 1];
671 					uint16 p2 = ProTrackerPeriodTable[i];
672 					if(p1 - period < (period - p2))
673 					{
674 						note = i + 23 + NOTE_MIN;
675 						break;
676 					}
677 				}
678 				note = i + 24 + NOTE_MIN;
679 				break;
680 			}
681 		}
682 	}
683 	m.note = static_cast<ModCommand::NOTE>(note);
684 	// Read Instrument
685 	m.instr = (data[2] >> 4) | (data[0] & 0x10);
686 	// Read Effect
687 	m.command = data[2] & 0x0F;
688 	m.param = data[3];
689 }
690 
691 
692 struct MODMagicResult
693 {
694 	const mpt::uchar *madeWithTracker = nullptr;
695 	uint32 invalidByteThreshold = MODSampleHeader::INVALID_BYTE_THRESHOLD;
696 	uint16 patternDataOffset    = 1084;
697 	CHANNELINDEX numChannels    = 0;
698 	bool isNoiseTracker         = false;
699 	bool isStartrekker          = false;
700 	bool isGenericMultiChannel  = false;
701 	bool setMODVBlankTiming     = false;
702 };
703 
704 
CheckMODMagic(const char magic[4],MODMagicResult & result)705 static bool CheckMODMagic(const char magic[4], MODMagicResult &result)
706 {
707 	if(IsMagic(magic, "M.K.")      // ProTracker and compatible
708 	   || IsMagic(magic, "M!K!")   // ProTracker (>64 patterns)
709 	   || IsMagic(magic, "PATT")   // ProTracker 3.6
710 	   || IsMagic(magic, "NSMS")   // kingdomofpleasure.mod by bee hunter
711 	   || IsMagic(magic, "LARD"))  // judgement_day_gvine.mod by 4-mat
712 	{
713 		result.madeWithTracker = UL_("Generic ProTracker or compatible");
714 		result.numChannels = 4;
715 	} else if(IsMagic(magic, "M&K!")     // "His Master's Noise" musicdisk
716 	          || IsMagic(magic, "FEST")  // "His Master's Noise" musicdisk
717 	          || IsMagic(magic, "N.T."))
718 	{
719 		result.madeWithTracker = UL_("NoiseTracker");
720 		result.isNoiseTracker = true;
721 		result.numChannels = 4;
722 	} else if(IsMagic(magic, "OKTA")
723 	          || IsMagic(magic, "OCTA"))
724 	{
725 		// Oktalyzer
726 		result.madeWithTracker = UL_("Oktalyzer");
727 		result.numChannels = 8;
728 	} else if(IsMagic(magic, "CD81")
729 	          || IsMagic(magic, "CD61"))
730 	{
731 		// Octalyser on Atari STe/Falcon
732 		result.madeWithTracker = UL_("Octalyser (Atari)");
733 		result.numChannels = magic[2] - '0';
734 	} else if(IsMagic(magic, "M\0\0\0") || IsMagic(magic, "8\0\0\0"))
735 	{
736 		// Inconexia demo by Iguana, delta samples (https://www.pouet.net/prod.php?which=830)
737 		result.madeWithTracker = UL_("Inconexia demo (delta samples)");
738 		result.invalidByteThreshold = MODSampleHeader::INVALID_BYTE_FRAGILE_THRESHOLD;
739 		result.numChannels = (magic[0] == '8') ? 8 : 4;
740 	} else if(!memcmp(magic, "FA0", 3) && magic[3] >= '4' && magic[3] <= '8')
741 	{
742 		// Digital Tracker on Atari Falcon
743 		result.madeWithTracker = UL_("Digital Tracker");
744 		result.numChannels = magic[3] - '0';
745 		// Digital Tracker MODs contain four bytes (00 40 00 00) right after the magic bytes which don't seem to do anything special.
746 		result.patternDataOffset = 1088;
747 	} else if((!memcmp(magic, "FLT", 3) || !memcmp(magic, "EXO", 3)) && magic[3] >= '4' && magic[3] <= '9')
748 	{
749 		// FLTx / EXOx - Startrekker by Exolon / Fairlight
750 		result.madeWithTracker = UL_("Startrekker");
751 		result.isStartrekker = true;
752 		result.setMODVBlankTiming = true;
753 		result.numChannels = magic[3] - '0';
754 	} else if(magic[0] >= '1' && magic[0] <= '9' && !memcmp(magic + 1, "CHN", 3))
755 	{
756 		// xCHN - Many trackers
757 		result.madeWithTracker = UL_("Generic MOD-compatible Tracker");
758 		result.isGenericMultiChannel = true;
759 		result.numChannels = magic[0] - '0';
760 	} else if(magic[0] >= '1' && magic[0] <= '9' && magic[1] >= '0' && magic[1] <= '9'
761 	          && (!memcmp(magic + 2, "CH", 2) || !memcmp(magic + 2, "CN", 2)))
762 	{
763 		// xxCN / xxCH - Many trackers
764 		result.madeWithTracker = UL_("Generic MOD-compatible Tracker");
765 		result.isGenericMultiChannel = true;
766 		result.numChannels = (magic[0] - '0') * 10 + magic[1] - '0';
767 	} else if(!memcmp(magic, "TDZ", 3) && magic[3] >= '1' && magic[3] <= '9')
768 	{
769 		// TDZx - TakeTracker (only TDZ1-TDZ3 should exist, but historically this code only supported 4-9 channels, so we keep those for the unlikely case that they were actually used for something)
770 		result.madeWithTracker = UL_("TakeTracker");
771 		result.numChannels = magic[3] - '0';
772 	} else
773 	{
774 		return false;
775 	}
776 	return true;
777 }
778 
779 
ProbeFileHeaderMOD(MemoryFileReader file,const uint64 * pfilesize)780 CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMOD(MemoryFileReader file, const uint64 *pfilesize)
781 {
782 	if(!file.CanRead(1080 + 4))
783 	{
784 		return ProbeWantMoreData;
785 	}
786 	file.Seek(1080);
787 	char magic[4];
788 	file.ReadArray(magic);
789 	MODMagicResult modMagicResult;
790 	if(!CheckMODMagic(magic, modMagicResult))
791 	{
792 		return ProbeFailure;
793 	}
794 
795 	file.Seek(20);
796 	uint32 invalidBytes = 0;
797 	for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
798 	{
799 		MODSampleHeader sampleHeader;
800 		file.ReadStruct(sampleHeader);
801 		invalidBytes += sampleHeader.GetInvalidByteScore();
802 	}
803 	if(invalidBytes > modMagicResult.invalidByteThreshold)
804 	{
805 		return ProbeFailure;
806 	}
807 
808 	MPT_UNREFERENCED_PARAMETER(pfilesize);
809 	return ProbeSuccess;
810 }
811 
812 
ReadMOD(FileReader & file,ModLoadingFlags loadFlags)813 bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags)
814 {
815 	char magic[4];
816 	if(!file.Seek(1080) || !file.ReadArray(magic))
817 	{
818 		return false;
819 	}
820 
821 	InitializeGlobals(MOD_TYPE_MOD);
822 
823 	MODMagicResult modMagicResult;
824 	if(!CheckMODMagic(magic, modMagicResult)
825 	   || modMagicResult.numChannels < 1
826 	   || modMagicResult.numChannels > MAX_BASECHANNELS)
827 	{
828 		return false;
829 	}
830 
831 	if(loadFlags == onlyVerifyHeader)
832 	{
833 		return true;
834 	}
835 
836 	m_nChannels = modMagicResult.numChannels;
837 
838 	bool isNoiseTracker = modMagicResult.isNoiseTracker;
839 	bool isStartrekker = modMagicResult.isStartrekker;
840 	bool isGenericMultiChannel = modMagicResult.isGenericMultiChannel;
841 	bool isInconexia = IsMagic(magic, "M\0\0\0") || IsMagic(magic, "8\0\0\0");
842 	// A loop length of zero will freeze ProTracker, so assume that modules having such a value were not meant to be played on Amiga. Fixes LHS_MI.MOD
843 	bool hasRepLen0 = false;
844 	// Empty sample slots typically should have a default volume of 0 in ProTracker
845 	bool hasEmptySampleWithVolume = false;
846 	if(modMagicResult.setMODVBlankTiming)
847 	{
848 		m_playBehaviour.set(kMODVBlankTiming);
849 	}
850 
851 	// Startrekker 8 channel mod (needs special treatment, see below)
852 	const bool isFLT8 = isStartrekker && m_nChannels == 8;
853 	// Only apply VBlank tests to M.K. (ProTracker) modules.
854 	const bool isMdKd = IsMagic(magic, "M.K.");
855 	// Adjust finetune values for modules saved with "His Master's Noisetracker"
856 	const bool isHMNT = IsMagic(magic, "M&K!") || IsMagic(magic, "FEST");
857 	bool maybeWOW = isMdKd;
858 
859 	// Reading song title
860 	file.Seek(0);
861 	file.ReadString<mpt::String::spacePadded>(m_songName, 20);
862 
863 	// Load Sample Headers
864 	SmpLength totalSampleLen = 0, wowSampleLen = 0;
865 	m_nSamples = 31;
866 	uint32 invalidBytes = 0;
867 	for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
868 	{
869 		MODSampleHeader sampleHeader;
870 		invalidBytes += ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], m_nChannels == 4);
871 		totalSampleLen += Samples[smp].nLength;
872 
873 		if(isHMNT)
874 			Samples[smp].nFineTune = -static_cast<int8>(sampleHeader.finetune << 3);
875 		else if(Samples[smp].nLength > 65535)
876 			isNoiseTracker = false;
877 
878 		if(sampleHeader.length && !sampleHeader.loopLength)
879 			hasRepLen0 = true;
880 		else if(!sampleHeader.length && sampleHeader.volume == 64)
881 			hasEmptySampleWithVolume = true;
882 
883 		if(maybeWOW)
884 		{
885 			// Some WOW files rely on sample length 1 being counted as well
886 			wowSampleLen += sampleHeader.length * 2;
887 			// WOW files are converted 669 files, which don't support finetune or default volume
888 			if(sampleHeader.finetune)
889 				maybeWOW = false;
890 			else if(sampleHeader.length > 0 && sampleHeader.volume != 64)
891 				maybeWOW = false;
892 		}
893 	}
894 	// If there is too much binary garbage in the sample headers, reject the file.
895 	if(invalidBytes > modMagicResult.invalidByteThreshold)
896 	{
897 		return false;
898 	}
899 
900 	// Read order information
901 	MODFileHeader fileHeader;
902 	file.ReadStruct(fileHeader);
903 
904 	file.Seek(modMagicResult.patternDataOffset);
905 
906 	if(fileHeader.restartPos > 0)
907 		maybeWOW = false;
908 	if(!maybeWOW)
909 		wowSampleLen = 0;
910 
911 	ReadOrderFromArray(Order(), fileHeader.orderList);
912 
913 	ORDERINDEX realOrders = fileHeader.numOrders;
914 	if(realOrders > 128)
915 	{
916 		// beatwave.mod by Sidewinder claims to have 129 orders. (MD5: 8a029ac498d453beb929db9a73c3c6b4, SHA1: f7b76fb9f477b07a2e78eb10d8624f0df262cde7 - the version from ModArchive, not ModLand)
917 		realOrders = 128;
918 	} else if(realOrders == 0)
919 	{
920 		// Is this necessary?
921 		realOrders = 128;
922 		while(realOrders > 1 && Order()[realOrders - 1] == 0)
923 		{
924 			realOrders--;
925 		}
926 	}
927 
928 	// Get number of patterns (including some order list sanity checks)
929 	PATTERNINDEX numPatterns = GetNumPatterns(file, Order(), realOrders, totalSampleLen, m_nChannels, wowSampleLen, false);
930 	if(maybeWOW && GetNumChannels() == 8)
931 	{
932 		// M.K. with 8 channels = Mod's Grave
933 		modMagicResult.madeWithTracker = UL_("Mod's Grave");
934 		isGenericMultiChannel = true;
935 	}
936 
937 	if(isFLT8)
938 	{
939 		// FLT8 has only even order items, so divide by two.
940 		for(auto &pat : Order())
941 		{
942 			pat /= 2u;
943 		}
944 	}
945 
946 	// Restart position sanity checks
947 	realOrders--;
948 	Order().SetRestartPos(fileHeader.restartPos);
949 
950 	// (Ultimate) Soundtracker didn't have a restart position, but instead stored a default tempo in this value.
951 	// The default value for this is 0x78 (120 BPM). This is probably the reason why some M.K. modules
952 	// have this weird restart position. I think I've read somewhere that NoiseTracker actually writes 0x78 there.
953 	// M.K. files that have restart pos == 0x78: action's batman by DJ Uno, VALLEY.MOD, WormsTDC.MOD, ZWARTZ.MOD
954 	// Files that have an order list longer than 0x78 with restart pos = 0x78: my_shoe_is_barking.mod, papermix.mod
955 	// - in both cases it does not appear like the restart position should be used.
956 	MPT_ASSERT(fileHeader.restartPos != 0x78 || fileHeader.restartPos + 1u >= realOrders);
957 	if(fileHeader.restartPos > realOrders || (fileHeader.restartPos == 0x78 && m_nChannels == 4))
958 	{
959 		Order().SetRestartPos(0);
960 	}
961 
962 	m_nDefaultSpeed = 6;
963 	m_nDefaultTempo.Set(125);
964 	m_nMinPeriod = 14 * 4;
965 	m_nMaxPeriod = 3424 * 4;
966 	// Prevent clipping based on number of channels... If all channels are playing at full volume, "256 / #channels"
967 	// is the maximum possible sample pre-amp without getting distortion (Compatible mix levels given).
968 	// The more channels we have, the less likely it is that all of them are used at the same time, though, so cap at 32...
969 	m_nSamplePreAmp = Clamp(256 / m_nChannels, 32, 128);
970 	m_SongFlags.reset();  // SONG_ISAMIGA will be set conditionally
971 
972 	// Setup channel pan positions and volume
973 	SetupMODPanning();
974 
975 	// Before loading patterns, apply some heuristics:
976 	// - Scan patterns to check if file could be a NoiseTracker file in disguise.
977 	//   In this case, the parameter of Dxx commands needs to be ignored.
978 	// - Use the same code to find notes that would be out-of-range on Amiga.
979 	// - Detect 7-bit panning and whether 8xx / E8x commands should be interpreted as panning at all.
980 	bool onlyAmigaNotes = true;
981 	bool fix7BitPanning = false;
982 	uint8 maxPanning = 0;  // For detecting 8xx-as-sync
983 	const uint8 ENABLE_MOD_PANNING_THRESHOLD = 0x30;
984 	if(!isNoiseTracker)
985 	{
986 		bool leftPanning = false, extendedPanning = false;  // For detecting 800-880 panning
987 		isNoiseTracker = isMdKd;
988 		for(PATTERNINDEX pat = 0; pat < numPatterns; pat++)
989 		{
990 			uint16 patternBreaks = 0;
991 
992 			for(uint32 i = 0; i < 256; i++)
993 			{
994 				ModCommand m;
995 				ReadMODPatternEntry(file, m);
996 				if(!m.IsAmigaNote())
997 				{
998 					isNoiseTracker = onlyAmigaNotes = false;
999 				}
1000 				if((m.command > 0x06 && m.command < 0x0A)
1001 					|| (m.command == 0x0E && m.param > 0x01)
1002 					|| (m.command == 0x0F && m.param > 0x1F)
1003 					|| (m.command == 0x0D && ++patternBreaks > 1))
1004 				{
1005 					isNoiseTracker = false;
1006 				}
1007 				if(m.command == 0x08)
1008 				{
1009 					maxPanning = std::max(maxPanning, m.param);
1010 					if(m.param < 0x80)
1011 						leftPanning = true;
1012 					else if(m.param > 0x8F && m.param != 0xA4)
1013 						extendedPanning = true;
1014 				} else if(m.command == 0x0E && (m.param & 0xF0) == 0x80)
1015 				{
1016 					maxPanning = std::max(maxPanning, static_cast<uint8>((m.param & 0x0F) << 4));
1017 				}
1018 			}
1019 		}
1020 		fix7BitPanning = leftPanning && !extendedPanning && maxPanning >= ENABLE_MOD_PANNING_THRESHOLD;
1021 	}
1022 	file.Seek(modMagicResult.patternDataOffset);
1023 
1024 	const CHANNELINDEX readChannels = (isFLT8 ? 4 : m_nChannels); // 4 channels per pattern in FLT8 format.
1025 	if(isFLT8) numPatterns++; // as one logical pattern consists of two real patterns in FLT8 format, the highest pattern number has to be increased by one.
1026 	bool hasTempoCommands = false, definitelyCIA = false;	// for detecting VBlank MODs
1027 	// Heuristic for rejecting E0x commands that are most likely not intended to actually toggle the Amiga LED filter, like in naen_leijasi_ptk.mod by ilmarque
1028 	bool filterState = false;
1029 	int filterTransitions = 0;
1030 
1031 	// Reading patterns
1032 	Patterns.ResizeArray(numPatterns);
1033 	for(PATTERNINDEX pat = 0; pat < numPatterns; pat++)
1034 	{
1035 		ModCommand *rowBase = nullptr;
1036 
1037 		if(isFLT8)
1038 		{
1039 			// FLT8: Only create "even" patterns and either write to channel 1 to 4 (even patterns) or 5 to 8 (odd patterns).
1040 			PATTERNINDEX actualPattern = pat / 2u;
1041 			if((pat % 2u) == 0 && !Patterns.Insert(actualPattern, 64))
1042 			{
1043 				break;
1044 			}
1045 			rowBase = Patterns[actualPattern].GetpModCommand(0, (pat % 2u) == 0 ? 0 : 4);
1046 		} else
1047 		{
1048 			if(!Patterns.Insert(pat, 64))
1049 			{
1050 				break;
1051 			}
1052 			rowBase = Patterns[pat].GetpModCommand(0, 0);
1053 		}
1054 
1055 		if(rowBase == nullptr || !(loadFlags & loadPatternData))
1056 		{
1057 			break;
1058 		}
1059 
1060 		// For detecting PT1x mode
1061 		std::vector<ModCommand::INSTR> lastInstrument(GetNumChannels(), 0);
1062 		std::vector<uint8> instrWithoutNoteCount(GetNumChannels(), 0);
1063 
1064 		for(ROWINDEX row = 0; row < 64; row++, rowBase += m_nChannels)
1065 		{
1066 			// If we have more than one Fxx command on this row and one can be interpreted as speed
1067 			// and the other as tempo, we can be rather sure that it is not a VBlank mod.
1068 			bool hasSpeedOnRow = false, hasTempoOnRow = false;
1069 
1070 			for(CHANNELINDEX chn = 0; chn < readChannels; chn++)
1071 			{
1072 				ModCommand &m = rowBase[chn];
1073 				ReadMODPatternEntry(file, m);
1074 
1075 				if(m.command || m.param)
1076 				{
1077 					if(isStartrekker && m.command == 0x0E)
1078 					{
1079 						// No support for Startrekker assembly macros
1080 						m.command = CMD_NONE;
1081 						m.param = 0;
1082 					} else if(isStartrekker && m.command == 0x0F && m.param > 0x1F)
1083 					{
1084 						// Startrekker caps speed at 31 ticks per row
1085 						m.param = 0x1F;
1086 					}
1087 					ConvertModCommand(m);
1088 				}
1089 
1090 				// Perform some checks for our heuristics...
1091 				if(m.command == CMD_TEMPO)
1092 				{
1093 					hasTempoOnRow = true;
1094 					if(m.param < 100)
1095 						hasTempoCommands = true;
1096 				} else if(m.command == CMD_SPEED)
1097 				{
1098 					hasSpeedOnRow = true;
1099 				} else if(m.command == CMD_PATTERNBREAK && isNoiseTracker)
1100 				{
1101 					m.param = 0;
1102 				} else if(m.command == CMD_PANNING8 && fix7BitPanning)
1103 				{
1104 					// Fix MODs with 7-bit + surround panning
1105 					if(m.param == 0xA4)
1106 					{
1107 						m.command = CMD_S3MCMDEX;
1108 						m.param = 0x91;
1109 					} else
1110 					{
1111 						m.param = mpt::saturate_cast<ModCommand::PARAM>(m.param * 2);
1112 					}
1113 				} else if(m.command == CMD_MODCMDEX && m.param < 0x10)
1114 				{
1115 					// Count LED filter transitions
1116 					bool newState = !(m.param & 0x01);
1117 					if(newState != filterState)
1118 					{
1119 						filterState = newState;
1120 						filterTransitions++;
1121 					}
1122 				}
1123 				if(m.note == NOTE_NONE && m.instr > 0 && !isFLT8)
1124 				{
1125 					if(lastInstrument[chn] > 0 && lastInstrument[chn] != m.instr)
1126 					{
1127 						// Arbitrary threshold for enabling sample swapping: 4 consecutive "sample swaps" in one pattern.
1128 						if(++instrWithoutNoteCount[chn] >= 4)
1129 						{
1130 							m_playBehaviour.set(kMODSampleSwap);
1131 						}
1132 					}
1133 				} else if(m.note != NOTE_NONE)
1134 				{
1135 					instrWithoutNoteCount[chn] = 0;
1136 				}
1137 				if(m.instr != 0)
1138 				{
1139 					lastInstrument[chn] = m.instr;
1140 				}
1141 			}
1142 			if(hasSpeedOnRow && hasTempoOnRow)
1143 				definitelyCIA = true;
1144 		}
1145 	}
1146 
1147 	if(onlyAmigaNotes && !hasRepLen0 && (IsMagic(magic, "M.K.") || IsMagic(magic, "M!K!") || IsMagic(magic, "PATT")))
1148 	{
1149 		// M.K. files that don't exceed the Amiga note limit (fixes mod.mothergoose)
1150 		m_SongFlags.set(SONG_AMIGALIMITS);
1151 		// Need this for professionaltracker.mod by h0ffman (SHA1: 9a7c52cbad73ed2a198ee3fa18d3704ea9f546ff)
1152 		m_SongFlags.set(SONG_PT_MODE);
1153 		m_playBehaviour.set(kMODSampleSwap);
1154 		m_playBehaviour.set(kMODOutOfRangeNoteDelay);
1155 		m_playBehaviour.set(kMODTempoOnSecondTick);
1156 		// Arbitrary threshold for deciding that 8xx effects are only used as sync markers
1157 		if(maxPanning < ENABLE_MOD_PANNING_THRESHOLD)
1158 		{
1159 			m_playBehaviour.set(kMODIgnorePanning);
1160 			if(fileHeader.restartPos != 0x7F)
1161 			{
1162 				// Don't enable these hacks for ScreamTracker modules (restart position = 0x7F), to fix e.g. sample 10 in BASIC001.MOD (SHA1: 11298a5620e677beaa50bd4ed00c3710b75c81af)
1163 				// Note: restart position = 0x7F can also be found in ProTracker modules, e.g. professionaltracker.mod by h0ffman
1164 				m_playBehaviour.set(kMODOneShotLoops);
1165 			}
1166 		}
1167 	} else if(!onlyAmigaNotes && fileHeader.restartPos == 0x7F && isMdKd && fileHeader.restartPos + 1u >= realOrders)
1168 	{
1169 		modMagicResult.madeWithTracker = UL_("Scream Tracker");
1170 	}
1171 
1172 	if(onlyAmigaNotes && !isGenericMultiChannel && filterTransitions < 7)
1173 	{
1174 		m_SongFlags.set(SONG_ISAMIGA);
1175 	}
1176 	if(isGenericMultiChannel || isMdKd)
1177 	{
1178 		m_playBehaviour.set(kFT2MODTremoloRampWaveform);
1179 	}
1180 	if(isInconexia)
1181 	{
1182 		m_playBehaviour.set(kMODIgnorePanning);
1183 	}
1184 
1185 	// Reading samples
1186 	if(loadFlags & loadSampleData)
1187 	{
1188 		file.Seek(modMagicResult.patternDataOffset + (readChannels * 64 * 4) * numPatterns);
1189 		for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
1190 		{
1191 			ModSample &sample = Samples[smp];
1192 			if(sample.nLength)
1193 			{
1194 				SampleIO::Encoding encoding = SampleIO::signedPCM;
1195 				if(isInconexia)
1196 					encoding = SampleIO::deltaPCM;
1197 				else if(file.ReadMagic("ADPCM"))
1198 					encoding = SampleIO::ADPCM;
1199 
1200 				SampleIO sampleIO(
1201 					SampleIO::_8bit,
1202 					SampleIO::mono,
1203 					SampleIO::littleEndian,
1204 					encoding);
1205 
1206 				// Fix sample 6 in MOD.shorttune2, which has a replen longer than the sample itself.
1207 				// ProTracker reads beyond the end of the sample when playing. Normally samples are
1208 				// adjacent in PT's memory, so we simply read into the next sample in the file.
1209 				// On the other hand, the loop points in Purple Motions's SOUL-O-M.MOD are completely broken and shouldn't be treated like this.
1210 				// As it was most likely written in Scream Tracker, it has empty sample slots with a default volume of 64, which we use for
1211 				// rejecting this quirk for that file.
1212 				FileReader::off_t nextSample = file.GetPosition() + sampleIO.CalculateEncodedSize(sample.nLength);
1213 				if(isMdKd && onlyAmigaNotes && !hasEmptySampleWithVolume)
1214 					sample.nLength = std::max(sample.nLength, sample.nLoopEnd);
1215 
1216 				sampleIO.ReadSample(sample, file);
1217 				file.Seek(nextSample);
1218 			}
1219 		}
1220 	}
1221 
1222 #if defined(MPT_EXTERNAL_SAMPLES) || defined(MPT_BUILD_FUZZER)
1223 	// Detect Startrekker files with external synth instruments.
1224 	// Note: Synthesized AM samples may overwrite existing samples (e.g. sample 1 in fa.worse face.mod),
1225 	// hence they are loaded here after all regular samples have been loaded.
1226 	if((loadFlags & loadSampleData) && isStartrekker)
1227 	{
1228 #ifdef MPT_EXTERNAL_SAMPLES
1229 		std::optional<InputFile> amFile;
1230 		FileReader amData;
1231 		if(file.GetOptionalFileName())
1232 		{
1233 			mpt::PathString filename = file.GetOptionalFileName().value();
1234 			// Find instrument definition file
1235 			const mpt::PathString exts[] = {P_(".nt"), P_(".NT"), P_(".as"), P_(".AS")};
1236 			for(const auto &ext : exts)
1237 			{
1238 				mpt::PathString infoName = filename + ext;
1239 				char stMagic[16];
1240 				if(infoName.IsFile())
1241 				{
1242 					amFile.emplace(infoName, SettingCacheCompleteFileBeforeLoading());
1243 					if(amFile->IsValid() && (amData = GetFileReader(*amFile)).IsValid() && amData.ReadArray(stMagic))
1244 					{
1245 						if(!memcmp(stMagic, "ST1.2 ModuleINFO", 16))
1246 							modMagicResult.madeWithTracker = UL_("Startrekker 1.2");
1247 						else if(!memcmp(stMagic, "ST1.3 ModuleINFO", 16))
1248 							modMagicResult.madeWithTracker = UL_("Startrekker 1.3");
1249 						else if(!memcmp(stMagic, "AudioSculpture10", 16))
1250 							modMagicResult.madeWithTracker = UL_("AudioSculpture 1.0");
1251 						else
1252 							continue;
1253 
1254 						if(amData.Seek(144))
1255 						{
1256 							// Looks like a valid instrument definition file!
1257 							m_nInstruments = 31;
1258 							break;
1259 						}
1260 					}
1261 				}
1262 			}
1263 		}
1264 #elif defined(MPT_BUILD_FUZZER)
1265 		// For fuzzing this part of the code, just take random data from patterns
1266 		FileReader amData = file.GetChunkAt(1084, 31 * 120);
1267 		m_nInstruments = 31;
1268 #endif
1269 
1270 		for(SAMPLEINDEX smp = 1; smp <= m_nInstruments; smp++)
1271 		{
1272 			// For Startrekker AM synthesis, we need instrument envelopes.
1273 			ModInstrument *ins = AllocateInstrument(smp, smp);
1274 			if(ins == nullptr)
1275 			{
1276 				break;
1277 			}
1278 			ins->name = m_szNames[smp];
1279 
1280 			AMInstrument am;
1281 			// Allow partial reads for fa.worse face.mod
1282 			if(amData.ReadStructPartial(am) && !memcmp(am.am, "AM", 2) && am.waveform < 4)
1283 			{
1284 				am.ConvertToMPT(Samples[smp], *ins, AccessPRNG());
1285 			}
1286 
1287 			// This extra padding is probably present to have identical block sizes for AM and FM instruments.
1288 			amData.Skip(120 - sizeof(AMInstrument));
1289 		}
1290 	}
1291 #endif  // MPT_EXTERNAL_SAMPLES || MPT_BUILD_FUZZER
1292 
1293 	// Fix VBlank MODs. Arbitrary threshold: 9 minutes (enough for Guitar Slinger...).
1294 	// Basically, this just converts all tempo commands into speed commands
1295 	// for MODs which are supposed to have VBlank timing (instead of CIA timing).
1296 	// There is no perfect way to do this, since both MOD types look the same,
1297 	// but the most reliable way is to simply check for extremely long songs
1298 	// (as this would indicate that e.g. a F30 command was really meant to set
1299 	// the ticks per row to 48, and not the tempo to 48 BPM).
1300 	// In the pattern loader above, a second condition is used: Only tempo commands
1301 	// below 100 BPM are taken into account. Furthermore, only M.K. (ProTracker)
1302 	// modules are checked.
1303 	if(isMdKd && hasTempoCommands && !definitelyCIA)
1304 	{
1305 		const double songTime = GetLength(eNoAdjust).front().duration;
1306 		if(songTime >= 540.0)
1307 		{
1308 			m_playBehaviour.set(kMODVBlankTiming);
1309 			if(GetLength(eNoAdjust, GetLengthTarget(songTime)).front().targetReached)
1310 			{
1311 				// This just makes things worse, song is at least as long as in CIA mode (e.g. in "Stary Hallway" by Neurodancer)
1312 				// Obviously we should keep using CIA timing then...
1313 				m_playBehaviour.reset(kMODVBlankTiming);
1314 			} else
1315 			{
1316 				modMagicResult.madeWithTracker = UL_("ProTracker (VBlank)");
1317 			}
1318 		}
1319 	}
1320 
1321 	std::transform(std::begin(magic), std::end(magic), std::begin(magic), [](unsigned char c) -> unsigned char { return (c < ' ') ? ' ' : c; });
1322 	m_modFormat.formatName = MPT_UFORMAT("ProTracker MOD ({})")(mpt::ToUnicode(mpt::Charset::ASCII, std::string(std::begin(magic), std::end(magic))));
1323 	m_modFormat.type = U_("mod");
1324 	if(modMagicResult.madeWithTracker)
1325 		m_modFormat.madeWithTracker = modMagicResult.madeWithTracker;
1326 	m_modFormat.charset = mpt::Charset::ISO8859_1;
1327 
1328 	return true;
1329 }
1330 
1331 
1332 // Check if a name string is valid (i.e. doesn't contain binary garbage data)
1333 template <size_t N>
CountInvalidChars(const char (& name)[N])1334 static uint32 CountInvalidChars(const char (&name)[N])
1335 {
1336 	uint32 invalidChars = 0;
1337 	for(int8 c : name)  // char can be signed or unsigned
1338 	{
1339 		// Check for any Extended ASCII and control characters
1340 		if(c != 0 && c < ' ')
1341 			invalidChars++;
1342 	}
1343 	return invalidChars;
1344 }
1345 
1346 
1347 // We'll have to do some heuristic checks to find out whether this is an old Ultimate Soundtracker module
1348 // or if it was made with the newer Soundtracker versions.
1349 // Thanks for Fraggie for this information! (https://www.un4seen.com/forum/?topic=14471.msg100829#msg100829)
1350 enum STVersions
1351 {
1352 	UST1_00,              // Ultimate Soundtracker 1.0-1.21 (K. Obarski)
1353 	UST1_80,              // Ultimate Soundtracker 1.8-2.0 (K. Obarski)
1354 	ST2_00_Exterminator,  // SoundTracker 2.0 (The Exterminator), D.O.C. Sountracker II (Unknown/D.O.C.)
1355 	ST_III,               // Defjam Soundtracker III (Il Scuro/Defjam), Alpha Flight SoundTracker IV (Alpha Flight), D.O.C. SoundTracker IV (Unknown/D.O.C.), D.O.C. SoundTracker VI (Unknown/D.O.C.)
1356 	ST_IX,                // D.O.C. SoundTracker IX (Unknown/D.O.C.)
1357 	MST1_00,              // Master Soundtracker 1.0 (Tip/The New Masters)
1358 	ST2_00,               // SoundTracker 2.0, 2.1, 2.2 (Unknown/D.O.C.)
1359 };
1360 
1361 
1362 
1363 struct M15FileHeaders
1364 {
1365 	char            songname[20];
1366 	MODSampleHeader sampleHeaders[15];
1367 	MODFileHeader   fileHeader;
1368 };
1369 
1370 MPT_BINARY_STRUCT(M15FileHeaders, 20 + 15 * 30 + 130)
1371 
1372 
ValidateHeader(const M15FileHeaders & fileHeaders)1373 static bool ValidateHeader(const M15FileHeaders &fileHeaders)
1374 {
1375 	// In theory, sample and song names should only ever contain printable ASCII chars and null.
1376 	// However, there are quite a few SoundTracker modules in the wild with random
1377 	// characters. To still be able to distguish them from other formats, we just reject
1378 	// files with *too* many bogus characters. Arbitrary threshold: 48 bogus characters in total
1379 	// or more than 5 invalid characters just in the title alone.
1380 	uint32 invalidChars = CountInvalidChars(fileHeaders.songname);
1381 	if(invalidChars > 5)
1382 	{
1383 		return false;
1384 	}
1385 
1386 	SmpLength totalSampleLen = 0;
1387 	uint8 allVolumes = 0;
1388 
1389 	for(SAMPLEINDEX smp = 0; smp < 15; smp++)
1390 	{
1391 		const MODSampleHeader &sampleHeader = fileHeaders.sampleHeaders[smp];
1392 
1393 		invalidChars += CountInvalidChars(sampleHeader.name);
1394 
1395 		// Sanity checks - invalid character count adjusted for ata.mod (MD5 937b79b54026fa73a1a4d3597c26eace, SHA1 3322ca62258adb9e0ae8e9afe6e0c29d39add874)
1396 		if(invalidChars > 48
1397 		   || sampleHeader.volume > 64
1398 		   || sampleHeader.finetune != 0
1399 		   || sampleHeader.length > 32768)
1400 		{
1401 			return false;
1402 		}
1403 
1404 		totalSampleLen += sampleHeader.length;
1405 		allVolumes |= sampleHeader.volume;
1406 	}
1407 
1408 	// Reject any files with no (or only silent) samples at all, as this might just be a random binary file (e.g. ID3 tags with tons of padding)
1409 	if(totalSampleLen == 0 || allVolumes == 0)
1410 	{
1411 		return false;
1412 	}
1413 
1414 	// Sanity check: No more than 128 positions. ST's GUI limits tempo to [1, 220].
1415 	// There are some mods with a tempo of 0 (explora3-death.mod) though, so ignore the lower limit.
1416 	if(fileHeaders.fileHeader.numOrders > 128 || fileHeaders.fileHeader.restartPos > 220)
1417 	{
1418 		return false;
1419 	}
1420 
1421 	uint8 maxPattern = *std::max_element(std::begin(fileHeaders.fileHeader.orderList), std::end(fileHeaders.fileHeader.orderList));
1422 	// Sanity check: 64 patterns max.
1423 	if(maxPattern > 63)
1424 	{
1425 		return false;
1426 	}
1427 
1428 	// No playable song, and lots of null values => most likely a sparse binary file but not a module
1429 	if(fileHeaders.fileHeader.restartPos == 0 && fileHeaders.fileHeader.numOrders == 0 && maxPattern == 0)
1430 	{
1431 		return false;
1432 	}
1433 
1434 	return true;
1435 }
1436 
1437 
1438 template <typename TFileReader>
ValidateFirstM15Pattern(TFileReader & file)1439 static bool ValidateFirstM15Pattern(TFileReader &file)
1440 {
1441 	// threshold is chosen as: [threshold for all patterns combined] / [max patterns] * [margin, do not reject too much]
1442 	return ValidateMODPatternData(file, 512 / 64 * 2, false);
1443 }
1444 
1445 
ProbeFileHeaderM15(MemoryFileReader file,const uint64 * pfilesize)1446 CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderM15(MemoryFileReader file, const uint64 *pfilesize)
1447 {
1448 	M15FileHeaders fileHeaders;
1449 	if(!file.ReadStruct(fileHeaders))
1450 	{
1451 		return ProbeWantMoreData;
1452 	}
1453 	if(!ValidateHeader(fileHeaders))
1454 	{
1455 		return ProbeFailure;
1456 	}
1457 	if(!file.CanRead(sizeof(MODPatternData)))
1458 	{
1459 		return ProbeWantMoreData;
1460 	}
1461 	if(!ValidateFirstM15Pattern(file))
1462 	{
1463 		return ProbeFailure;
1464 	}
1465 	MPT_UNREFERENCED_PARAMETER(pfilesize);
1466 	return ProbeSuccess;
1467 }
1468 
1469 
ReadM15(FileReader & file,ModLoadingFlags loadFlags)1470 bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
1471 {
1472 	file.Rewind();
1473 
1474 	M15FileHeaders fileHeaders;
1475 	if(!file.ReadStruct(fileHeaders))
1476 	{
1477 		return false;
1478 	}
1479 	if(!ValidateHeader(fileHeaders))
1480 	{
1481 		return false;
1482 	}
1483 	if(!ValidateFirstM15Pattern(file))
1484 	{
1485 		return false;
1486 	}
1487 
1488 	char songname[20];
1489 	std::memcpy(songname, fileHeaders.songname, 20);
1490 
1491 	InitializeGlobals(MOD_TYPE_MOD);
1492 	m_playBehaviour.reset(kMODOneShotLoops);
1493 	m_playBehaviour.set(kMODIgnorePanning);
1494 	m_playBehaviour.set(kMODSampleSwap);  // untested
1495 	m_nChannels = 4;
1496 
1497 	STVersions minVersion = UST1_00;
1498 
1499 	bool hasDiskNames = true;
1500 	SmpLength totalSampleLen = 0;
1501 	m_nSamples = 15;
1502 
1503 	file.Seek(20);
1504 	for(SAMPLEINDEX smp = 1; smp <= 15; smp++)
1505 	{
1506 		MODSampleHeader sampleHeader;
1507 		ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], true);
1508 
1509 		totalSampleLen += Samples[smp].nLength;
1510 
1511 		if(m_szNames[smp][0] && ((memcmp(m_szNames[smp].buf, "st-", 3) && memcmp(m_szNames[smp].buf, "ST-", 3)) || m_szNames[smp][5] != ':'))
1512 		{
1513 			// Ultimate Soundtracker 1.8 and D.O.C. SoundTracker IX always have sample names containing disk names.
1514 			hasDiskNames = false;
1515 		}
1516 
1517 		// Loop start is always in bytes, not words, so don't trust the auto-fix magic in the sample header conversion (fixes loop of "st-01:asia" in mod.drag 10)
1518 		if(sampleHeader.loopLength > 1)
1519 		{
1520 			Samples[smp].nLoopStart = sampleHeader.loopStart;
1521 			Samples[smp].nLoopEnd = sampleHeader.loopStart + sampleHeader.loopLength * 2;
1522 			Samples[smp].SanitizeLoops();
1523 		}
1524 
1525 		// UST only handles samples up to 9999 bytes. Master Soundtracker 1.0 and SoundTracker 2.0 introduce 32KB samples.
1526 		if(sampleHeader.length > 4999 || sampleHeader.loopStart > 9999)
1527 			minVersion = std::max(minVersion, MST1_00);
1528 	}
1529 
1530 	MODFileHeader fileHeader;
1531 	file.ReadStruct(fileHeader);
1532 
1533 	ReadOrderFromArray(Order(), fileHeader.orderList);
1534 	PATTERNINDEX numPatterns = GetNumPatterns(file, Order(), fileHeader.numOrders, totalSampleLen, m_nChannels, 0, true);
1535 
1536 	// Most likely just a file with lots of NULs at the start
1537 	if(fileHeader.restartPos == 0 && fileHeader.numOrders == 0 && numPatterns <= 1)
1538 	{
1539 		return false;
1540 	}
1541 
1542 	// Let's see if the file is too small (including some overhead for broken files like sll7.mod or ghostbus.mod)
1543 	if(file.BytesLeft() + 65536 < numPatterns * 64u * 4u * 4u + totalSampleLen)
1544 		return false;
1545 
1546 	if(loadFlags == onlyVerifyHeader)
1547 		return true;
1548 
1549 	// Now we can be pretty sure that this is a valid Soundtracker file. Set up default song settings.
1550 	// explora3-death.mod has a tempo of 0
1551 	if(!fileHeader.restartPos)
1552 		fileHeader.restartPos = 0x78;
1553 	// jjk55 by Jesper Kyd has a weird tempo set, but it needs to be ignored.
1554 	if(!memcmp(songname, "jjk55", 6))
1555 		fileHeader.restartPos = 0x78;
1556 	// Sample 7 in echoing.mod won't "loop" correctly if we don't convert the VBlank tempo.
1557 	m_nDefaultTempo.Set(125);
1558 	if(fileHeader.restartPos != 0x78)
1559 	{
1560 		// Convert to CIA timing
1561 		m_nDefaultTempo = TEMPO((709379.0 * 125.0 / 50.0) / ((240 - fileHeader.restartPos) * 122.0));
1562 		if(minVersion > UST1_80)
1563 		{
1564 			// D.O.C. SoundTracker IX re-introduced the variable tempo after some other versions dropped it.
1565 			minVersion = std::max(minVersion, hasDiskNames ? ST_IX : MST1_00);
1566 		} else
1567 		{
1568 			// Ultimate Soundtracker 1.8 adds variable tempo
1569 			minVersion = std::max(minVersion, hasDiskNames ? UST1_80 : ST2_00_Exterminator);
1570 		}
1571 	}
1572 	m_nMinPeriod = 113 * 4;
1573 	m_nMaxPeriod = 856 * 4;
1574 	m_nSamplePreAmp = 64;
1575 	m_SongFlags.set(SONG_PT_MODE);
1576 	m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, songname);
1577 
1578 	// Setup channel pan positions and volume
1579 	SetupMODPanning();
1580 
1581 	FileReader::off_t patOffset = file.GetPosition();
1582 
1583 	// Scan patterns to identify Ultimate Soundtracker modules.
1584 	uint32 illegalBytes = 0, totalNumDxx = 0;
1585 	for(PATTERNINDEX pat = 0; pat < numPatterns; pat++)
1586 	{
1587 		const bool patternInUse = mpt::contains(Order(), pat);
1588 		uint8 numDxx = 0;
1589 		uint8 emptyCmds = 0;
1590 		MODPatternData patternData;
1591 		file.ReadArray(patternData);
1592 		if(patternInUse)
1593 		{
1594 			illegalBytes += CountMalformedMODPatternData(patternData, false);
1595 			// Reject files that contain a lot of illegal pattern data.
1596 			// STK.the final remix (MD5 5ff13cdbd77211d1103be7051a7d89c9, SHA1 e94dba82a5da00a4758ba0c207eb17e3a89c3aa3)
1597 			// has one illegal byte, so we only reject after an arbitrary threshold has been passed.
1598 			// This also allows to play some rather damaged files like
1599 			// crockets.mod (MD5 995ed9f44cab995a0eeb19deb52e2a8b, SHA1 6c79983c3b7d55c9bc110b625eaa07ce9d75f369)
1600 			// but naturally we cannot recover the broken data.
1601 
1602 			// We only check patterns that are actually being used in the order list, because some bad rips of the
1603 			// "operation wolf" soundtrack have 15 patterns for several songs, but the last few patterns are just garbage.
1604 			// Apart from those hidden patterns, the files play fine.
1605 			// Example: operation wolf - wolf1.mod (MD5 739acdbdacd247fbefcac7bc2d8abe6b, SHA1 e6b4813daacbf95f41ce9ec3b22520a2ae07eed8)
1606 			if(illegalBytes > 512)
1607 				return false;
1608 		}
1609 		for(ROWINDEX row = 0; row < 64; row++)
1610 		{
1611 			for(CHANNELINDEX chn = 0; chn < 4; chn++)
1612 			{
1613 				const auto &data = patternData[row][chn];
1614 				const uint8 eff = data[2] & 0x0F, param = data[3];
1615 				// Check for empty space between the last Dxx command and the beginning of another pattern
1616 				if(emptyCmds != 0 && !memcmp(data.data(), "\0\0\0\0", 4))
1617 				{
1618 					emptyCmds++;
1619 					if(emptyCmds > 32)
1620 					{
1621 						// Since there is a lot of empty space after the last Dxx command,
1622 						// we assume it's supposed to be a pattern break effect.
1623 						minVersion = ST2_00;
1624 					}
1625 				} else
1626 				{
1627 					emptyCmds = 0;
1628 				}
1629 
1630 				switch(eff)
1631 				{
1632 				case 1:
1633 				case 2:
1634 					if(param > 0x1F && minVersion == UST1_80)
1635 					{
1636 						// If a 1xx / 2xx effect has a parameter greater than 0x20, it is assumed to be UST.
1637 						minVersion = hasDiskNames ? UST1_80 : UST1_00;
1638 					} else if(eff == 1 && param > 0 && param < 0x03)
1639 					{
1640 						// This doesn't look like an arpeggio.
1641 						minVersion = std::max(minVersion, ST2_00_Exterminator);
1642 					} else if(eff == 1 && (param == 0x37 || param == 0x47) && minVersion <= ST2_00_Exterminator)
1643 					{
1644 						// This suspiciously looks like an arpeggio.
1645 						// Catch sleepwalk.mod by Karsten Obarski, which has a default tempo of 125 rather than 120 in the header, so gets mis-identified as a later tracker version.
1646 						minVersion = hasDiskNames ? UST1_80 : UST1_00;
1647 					}
1648 					break;
1649 				case 0x0B:
1650 					minVersion = ST2_00;
1651 					break;
1652 				case 0x0C:
1653 				case 0x0D:
1654 				case 0x0E:
1655 					minVersion = std::max(minVersion, ST2_00_Exterminator);
1656 					if(eff == 0x0D)
1657 					{
1658 						emptyCmds = 1;
1659 						if(param == 0 && row == 0)
1660 						{
1661 							// Fix a possible tracking mistake in Blood Money title - who wants to do a pattern break on the first row anyway?
1662 							break;
1663 						}
1664 						numDxx++;
1665 					}
1666 					break;
1667 				case 0x0F:
1668 					minVersion = std::max(minVersion, ST_III);
1669 					break;
1670 				}
1671 			}
1672 		}
1673 
1674 		if(numDxx > 0 && numDxx < 3)
1675 		{
1676 			// Not many Dxx commands in one pattern means they were probably pattern breaks
1677 			minVersion = ST2_00;
1678 		}
1679 		totalNumDxx += numDxx;
1680 	}
1681 
1682 	// If there is a huge number of Dxx commands, this is extremely unlikely to be a  SoundTracker 2.0 module
1683 	if(totalNumDxx > numPatterns + 32u && minVersion == ST2_00)
1684 		minVersion = MST1_00;
1685 
1686 	file.Seek(patOffset);
1687 
1688 	// Reading patterns
1689 	if(loadFlags & loadPatternData)
1690 		Patterns.ResizeArray(numPatterns);
1691 	for(PATTERNINDEX pat = 0; pat < numPatterns; pat++)
1692 	{
1693 		MODPatternData patternData;
1694 		file.ReadArray(patternData);
1695 
1696 		if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64))
1697 		{
1698 			continue;
1699 		}
1700 
1701 		uint8 autoSlide[4] = {0, 0, 0, 0};
1702 		for(ROWINDEX row = 0; row < 64; row++)
1703 		{
1704 			PatternRow rowBase = Patterns[pat].GetpModCommand(row, 0);
1705 			for(CHANNELINDEX chn = 0; chn < 4; chn++)
1706 			{
1707 				ModCommand &m = rowBase[chn];
1708 				ReadMODPatternEntry(patternData[row][chn], m);
1709 
1710 				if(!m.param || m.command == 0x0E)
1711 				{
1712 					autoSlide[chn] = 0;
1713 				}
1714 				if(m.command || m.param)
1715 				{
1716 					if(autoSlide[chn] != 0)
1717 					{
1718 						if(autoSlide[chn] & 0xF0)
1719 						{
1720 							m.volcmd = VOLCMD_VOLSLIDEUP;
1721 							m.vol = autoSlide[chn] >> 4;
1722 						} else
1723 						{
1724 							m.volcmd = VOLCMD_VOLSLIDEDOWN;
1725 							m.vol = autoSlide[chn] & 0x0F;
1726 						}
1727 					}
1728 					if(m.command == 0x0D)
1729 					{
1730 						if(minVersion != ST2_00)
1731 						{
1732 							// Dxy is volume slide in some Soundtracker versions, D00 is a pattern break in the latest versions.
1733 							m.command = 0x0A;
1734 						} else
1735 						{
1736 							m.param = 0;
1737 						}
1738 					} else if(m.command == 0x0C)
1739 					{
1740 						// Volume is sent as-is to the chip, which ignores the highest bit.
1741 						m.param &= 0x7F;
1742 					} else if(m.command == 0x0E && (m.param > 0x01 || minVersion < ST_IX))
1743 					{
1744 						// Import auto-slides as normal slides and fake them using volume column slides.
1745 						m.command = 0x0A;
1746 						autoSlide[chn] = m.param;
1747 					} else if(m.command == 0x0F)
1748 					{
1749 						// Only the low nibble is evaluated in Soundtracker.
1750 						m.param &= 0x0F;
1751 					}
1752 
1753 					if(minVersion <= UST1_80)
1754 					{
1755 						// UST effects
1756 						switch(m.command)
1757 						{
1758 						case 0:
1759 							// jackdance.mod by Karsten Obarski has 0xy arpeggios...
1760 							if(m.param < 0x03)
1761 							{
1762 								m.command = CMD_NONE;
1763 							} else
1764 							{
1765 								m.command = CMD_ARPEGGIO;
1766 							}
1767 							break;
1768 						case 1:
1769 							m.command = CMD_ARPEGGIO;
1770 							break;
1771 						case 2:
1772 							if(m.param & 0x0F)
1773 							{
1774 								m.command = CMD_PORTAMENTOUP;
1775 								m.param &= 0x0F;
1776 							} else if(m.param >> 4)
1777 							{
1778 								m.command = CMD_PORTAMENTODOWN;
1779 								m.param >>= 4;
1780 							}
1781 							break;
1782 						default:
1783 							m.command = CMD_NONE;
1784 							break;
1785 						}
1786 					} else
1787 					{
1788 						ConvertModCommand(m);
1789 					}
1790 				} else
1791 				{
1792 					autoSlide[chn] = 0;
1793 				}
1794 			}
1795 		}
1796 	}
1797 
1798 	const mpt::uchar *madeWithTracker = UL_("");
1799 	switch(minVersion)
1800 	{
1801 	case UST1_00:
1802 		madeWithTracker = UL_("Ultimate Soundtracker 1.0-1.21");
1803 		break;
1804 	case UST1_80:
1805 		madeWithTracker = UL_("Ultimate Soundtracker 1.8-2.0");
1806 		break;
1807 	case ST2_00_Exterminator:
1808 		madeWithTracker = UL_("SoundTracker 2.0 / D.O.C. SoundTracker II");
1809 		break;
1810 	case ST_III:
1811 		madeWithTracker = UL_("Defjam Soundtracker III / Alpha Flight SoundTracker IV / D.O.C. SoundTracker IV / VI");
1812 		break;
1813 	case ST_IX:
1814 		madeWithTracker = UL_("D.O.C. SoundTracker IX");
1815 		break;
1816 	case MST1_00:
1817 		madeWithTracker = UL_("Master Soundtracker 1.0");
1818 		break;
1819 	case ST2_00:
1820 		madeWithTracker = UL_("SoundTracker 2.0 / 2.1 / 2.2");
1821 		break;
1822 	}
1823 
1824 	m_modFormat.formatName = U_("Soundtracker");
1825 	m_modFormat.type = U_("stk");
1826 	m_modFormat.madeWithTracker = madeWithTracker;
1827 	m_modFormat.charset = mpt::Charset::ISO8859_1;
1828 
1829 	// Reading samples
1830 	if(loadFlags & loadSampleData)
1831 	{
1832 		for(SAMPLEINDEX smp = 1; smp <= 15; smp++)
1833 		{
1834 			// Looped samples in (Ultimate) Soundtracker seem to ignore all sample data before the actual loop start.
1835 			// This avoids the clicks in the first sample of pretend.mod by Karsten Obarski.
1836 			file.Skip(Samples[smp].nLoopStart);
1837 			Samples[smp].nLength -= Samples[smp].nLoopStart;
1838 			Samples[smp].nLoopEnd -= Samples[smp].nLoopStart;
1839 			Samples[smp].nLoopStart = 0;
1840 			MODSampleHeader::GetSampleFormat().ReadSample(Samples[smp], file);
1841 		}
1842 	}
1843 
1844 	return true;
1845 }
1846 
1847 
ProbeFileHeaderICE(MemoryFileReader file,const uint64 * pfilesize)1848 CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize)
1849 {
1850 	if(!file.CanRead(1464 + 4))
1851 	{
1852 		return ProbeWantMoreData;
1853 	}
1854 	file.Seek(1464);
1855 	char magic[4];
1856 	file.ReadArray(magic);
1857 	if(!IsMagic(magic, "MTN\0") && !IsMagic(magic, "IT10"))
1858 	{
1859 		return ProbeFailure;
1860 	}
1861 	file.Seek(20);
1862 	uint32 invalidBytes = 0;
1863 	for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
1864 	{
1865 		MODSampleHeader sampleHeader;
1866 		if(!file.ReadStruct(sampleHeader))
1867 		{
1868 			return ProbeWantMoreData;
1869 		}
1870 		invalidBytes += sampleHeader.GetInvalidByteScore();
1871 	}
1872 	if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD)
1873 	{
1874 		return ProbeFailure;
1875 	}
1876 	const auto [numOrders, numTracks] = file.ReadArray<uint8, 2>();
1877 	if(numOrders > 128)
1878 	{
1879 		return ProbeFailure;
1880 	}
1881 	uint8 tracks[128 * 4];
1882 	file.ReadArray(tracks);
1883 	for(auto track : tracks)
1884 	{
1885 		if(track > numTracks)
1886 		{
1887 			return ProbeFailure;
1888 		}
1889 	}
1890 	MPT_UNREFERENCED_PARAMETER(pfilesize);
1891 	return ProbeSuccess;
1892 }
1893 
1894 
1895 // SoundTracker 2.6 / Ice Tracker variation of the MOD format
1896 // The only real difference to other SoundTracker formats is the way patterns are stored:
1897 // Every pattern consists of four independent, re-usable tracks.
ReadICE(FileReader & file,ModLoadingFlags loadFlags)1898 bool CSoundFile::ReadICE(FileReader &file, ModLoadingFlags loadFlags)
1899 {
1900 	char magic[4];
1901 	if(!file.Seek(1464) || !file.ReadArray(magic))
1902 	{
1903 		return false;
1904 	}
1905 
1906 	InitializeGlobals(MOD_TYPE_MOD);
1907 	m_playBehaviour.reset(kMODOneShotLoops);
1908 	m_playBehaviour.set(kMODIgnorePanning);
1909 	m_playBehaviour.set(kMODSampleSwap);  // untested
1910 
1911 	if(IsMagic(magic, "MTN\0"))
1912 	{
1913 		m_modFormat.formatName = U_("MnemoTroN SoundTracker");
1914 		m_modFormat.type = U_("st26");
1915 		m_modFormat.madeWithTracker = U_("SoundTracker 2.6");
1916 		m_modFormat.charset = mpt::Charset::ISO8859_1;
1917 	} else if(IsMagic(magic, "IT10"))
1918 	{
1919 		m_modFormat.formatName = U_("Ice Tracker");
1920 		m_modFormat.type = U_("ice");
1921 		m_modFormat.madeWithTracker = U_("Ice Tracker 1.0 / 1.1");
1922 		m_modFormat.charset = mpt::Charset::ISO8859_1;
1923 	} else
1924 	{
1925 		return false;
1926 	}
1927 
1928 	// Reading song title
1929 	file.Seek(0);
1930 	file.ReadString<mpt::String::spacePadded>(m_songName, 20);
1931 
1932 	// Load Samples
1933 	m_nSamples = 31;
1934 	uint32 invalidBytes = 0;
1935 	for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
1936 	{
1937 		MODSampleHeader sampleHeader;
1938 		invalidBytes += ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], true);
1939 	}
1940 	if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD)
1941 	{
1942 		return false;
1943 	}
1944 
1945 	const auto [numOrders, numTracks] = file.ReadArray<uint8, 2>();
1946 	if(numOrders > 128)
1947 	{
1948 		return false;
1949 	}
1950 
1951 	uint8 tracks[128 * 4];
1952 	file.ReadArray(tracks);
1953 	for(auto track : tracks)
1954 	{
1955 		if(track > numTracks)
1956 		{
1957 			return false;
1958 		}
1959 	}
1960 
1961 	if(loadFlags == onlyVerifyHeader)
1962 	{
1963 		return true;
1964 	}
1965 
1966 	// Now we can be pretty sure that this is a valid MOD file. Set up default song settings.
1967 	m_nChannels = 4;
1968 	m_nInstruments = 0;
1969 	m_nDefaultSpeed = 6;
1970 	m_nDefaultTempo.Set(125);
1971 	m_nMinPeriod = 14 * 4;
1972 	m_nMaxPeriod = 3424 * 4;
1973 	m_nSamplePreAmp = 64;
1974 	m_SongFlags.set(SONG_PT_MODE | SONG_IMPORTED);
1975 
1976 	// Setup channel pan positions and volume
1977 	SetupMODPanning();
1978 
1979 	// Reading patterns
1980 	Order().resize(numOrders);
1981 	uint8 speed[2] = {0, 0}, speedPos = 0;
1982 	Patterns.ResizeArray(numOrders);
1983 	for(PATTERNINDEX pat = 0; pat < numOrders; pat++)
1984 	{
1985 		Order()[pat] = pat;
1986 		if(!Patterns.Insert(pat, 64))
1987 			continue;
1988 
1989 		for(CHANNELINDEX chn = 0; chn < 4; chn++)
1990 		{
1991 			file.Seek(1468 + tracks[pat * 4 + chn] * 64u * 4u);
1992 			ModCommand *m = Patterns[pat].GetpModCommand(0, chn);
1993 
1994 			for(ROWINDEX row = 0; row < 64; row++, m += 4)
1995 			{
1996 				ReadMODPatternEntry(file, *m);
1997 
1998 				if((m->command || m->param)
1999 				   && !(m->command == 0x0E && m->param >= 0x10)     // Exx only sets filter
2000 				   && !(m->command >= 0x05 && m->command <= 0x09))  // These don't exist in ST2.6
2001 				{
2002 					ConvertModCommand(*m);
2003 				} else
2004 				{
2005 					m->command = CMD_NONE;
2006 				}
2007 			}
2008 		}
2009 
2010 		// Handle speed command with both nibbles set - this enables auto-swing (alternates between the two nibbles)
2011 		auto m = Patterns[pat].begin();
2012 		for(ROWINDEX row = 0; row < 64; row++)
2013 		{
2014 			for(CHANNELINDEX chn = 0; chn < 4; chn++, m++)
2015 			{
2016 				if(m->command == CMD_SPEED || m->command == CMD_TEMPO)
2017 				{
2018 					m->command = CMD_SPEED;
2019 					speedPos = 0;
2020 					if(m->param & 0xF0)
2021 					{
2022 						if((m->param >> 4) != (m->param & 0x0F) && (m->param & 0x0F) != 0)
2023 						{
2024 							// Both nibbles set
2025 							speed[0] = m->param >> 4;
2026 							speed[1] = m->param & 0x0F;
2027 							speedPos = 1;
2028 						}
2029 						m->param >>= 4;
2030 					}
2031 				}
2032 			}
2033 			if(speedPos)
2034 			{
2035 				Patterns[pat].WriteEffect(EffectWriter(CMD_SPEED, speed[speedPos - 1]).Row(row));
2036 				speedPos++;
2037 				if(speedPos == 3)
2038 					speedPos = 1;
2039 			}
2040 		}
2041 	}
2042 
2043 	// Reading samples
2044 	if(loadFlags & loadSampleData)
2045 	{
2046 		file.Seek(1468 + numTracks * 64u * 4u);
2047 		for(SAMPLEINDEX smp = 1; smp <= 31; smp++) if(Samples[smp].nLength)
2048 		{
2049 			SampleIO(
2050 				SampleIO::_8bit,
2051 				SampleIO::mono,
2052 				SampleIO::littleEndian,
2053 				SampleIO::signedPCM)
2054 				.ReadSample(Samples[smp], file);
2055 		}
2056 	}
2057 
2058 	return true;
2059 }
2060 
2061 
2062 
2063 struct PT36Header
2064 {
2065 	char     magicFORM[4]; // "FORM"
2066 	uint32be size;
2067 	char     magicMODL[4]; // "MODL"
2068 };
2069 
2070 MPT_BINARY_STRUCT(PT36Header, 12)
2071 
2072 
ValidateHeader(const PT36Header & fileHeader)2073 static bool ValidateHeader(const PT36Header &fileHeader)
2074 {
2075 	if(std::memcmp(fileHeader.magicFORM, "FORM", 4))
2076 	{
2077 		return false;
2078 	}
2079 	if(std::memcmp(fileHeader.magicMODL, "MODL", 4))
2080 	{
2081 		return false;
2082 	}
2083 	return true;
2084 }
2085 
2086 
ProbeFileHeaderPT36(MemoryFileReader file,const uint64 * pfilesize)2087 CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPT36(MemoryFileReader file, const uint64 *pfilesize)
2088 {
2089 	PT36Header fileHeader;
2090 	if(!file.ReadStruct(fileHeader))
2091 	{
2092 		return ProbeWantMoreData;
2093 	}
2094 	if(!ValidateHeader(fileHeader))
2095 	{
2096 		return ProbeFailure;
2097 	}
2098 	MPT_UNREFERENCED_PARAMETER(pfilesize);
2099 	return ProbeSuccess;
2100 }
2101 
2102 
2103 // ProTracker 3.6 version of the MOD format
2104 // Basically just a normal ProTracker mod with different magic, wrapped in an IFF file.
2105 // The "PTDT" chunk is passed to the normal MOD loader.
ReadPT36(FileReader & file,ModLoadingFlags loadFlags)2106 bool CSoundFile::ReadPT36(FileReader &file, ModLoadingFlags loadFlags)
2107 {
2108 	file.Rewind();
2109 
2110 	PT36Header fileHeader;
2111 	if(!file.ReadStruct(fileHeader))
2112 	{
2113 		return false;
2114 	}
2115 	if(!ValidateHeader(fileHeader))
2116 	{
2117 		return false;
2118 	}
2119 
2120 	bool ok = false, infoOk = false;
2121 	FileReader commentChunk;
2122 	mpt::ustring version;
2123 	PT36InfoChunk info;
2124 	MemsetZero(info);
2125 
2126 	// Go through IFF chunks...
2127 	PT36IffChunk iffHead;
2128 	if(!file.ReadStruct(iffHead))
2129 	{
2130 		return false;
2131 	}
2132 	// First chunk includes "MODL" magic in size
2133 	iffHead.chunksize -= 4;
2134 
2135 	do
2136 	{
2137 		// All chunk sizes include chunk header
2138 		iffHead.chunksize -= 8;
2139 		if(loadFlags == onlyVerifyHeader && iffHead.signature == PT36IffChunk::idPTDT)
2140 		{
2141 			return true;
2142 		}
2143 
2144 		FileReader chunk = file.ReadChunk(iffHead.chunksize);
2145 		if(!chunk.IsValid())
2146 		{
2147 			break;
2148 		}
2149 
2150 		switch(iffHead.signature)
2151 		{
2152 		case PT36IffChunk::idVERS:
2153 			chunk.Skip(4);
2154 			if(chunk.ReadMagic("PT") && iffHead.chunksize > 6)
2155 			{
2156 				chunk.ReadString<mpt::String::maybeNullTerminated>(version, mpt::Charset::ISO8859_1, iffHead.chunksize - 6);
2157 			}
2158 			break;
2159 
2160 		case PT36IffChunk::idINFO:
2161 			infoOk = chunk.ReadStruct(info);
2162 			break;
2163 
2164 		case PT36IffChunk::idCMNT:
2165 			commentChunk = chunk;
2166 			break;
2167 
2168 		case PT36IffChunk::idPTDT:
2169 			ok = ReadMOD(chunk, loadFlags);
2170 			break;
2171 		}
2172 	} while(file.ReadStruct(iffHead));
2173 
2174 	if(version.empty())
2175 	{
2176 		version = U_("3.6");
2177 	}
2178 
2179 	// both an info chunk and a module are required
2180 	if(ok && infoOk)
2181 	{
2182 		bool vblank = (info.flags & 0x100) == 0;
2183 		m_playBehaviour.set(kMODVBlankTiming, vblank);
2184 		if(info.volume != 0)
2185 			m_nSamplePreAmp = std::min(uint16(64), static_cast<uint16>(info.volume));
2186 		if(info.tempo != 0 && !vblank)
2187 			m_nDefaultTempo.Set(info.tempo);
2188 
2189 		if(info.name[0])
2190 			m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, info.name);
2191 
2192 		if(mpt::is_in_range(info.dateMonth, 1, 12) && mpt::is_in_range(info.dateDay, 1, 31) && mpt::is_in_range(info.dateHour, 0, 23)
2193 		   && mpt::is_in_range(info.dateMinute, 0, 59) && mpt::is_in_range(info.dateSecond, 0, 59))
2194 		{
2195 			FileHistory mptHistory;
2196 			mptHistory.loadDate.tm_year = info.dateYear;
2197 			mptHistory.loadDate.tm_mon = info.dateMonth - 1;
2198 			mptHistory.loadDate.tm_mday = info.dateDay;
2199 			mptHistory.loadDate.tm_hour = info.dateHour;
2200 			mptHistory.loadDate.tm_min = info.dateMinute;
2201 			mptHistory.loadDate.tm_sec = info.dateSecond;
2202 			m_FileHistory.push_back(mptHistory);
2203 		}
2204 	}
2205 	if(ok)
2206 	{
2207 		if(commentChunk.IsValid())
2208 		{
2209 			std::string author;
2210 			commentChunk.ReadString<mpt::String::maybeNullTerminated>(author, 32);
2211 			if(author != "UNNAMED AUTHOR")
2212 				m_songArtist = mpt::ToUnicode(mpt::Charset::ISO8859_1, author);
2213 			if(!commentChunk.NoBytesLeft())
2214 			{
2215 				m_songMessage.ReadFixedLineLength(commentChunk, commentChunk.BytesLeft(), 40, 0);
2216 			}
2217 		}
2218 
2219 		m_modFormat.madeWithTracker = U_("ProTracker ") + version;
2220 	}
2221 	m_SongFlags.set(SONG_PT_MODE);
2222 	m_playBehaviour.set(kMODIgnorePanning);
2223 	m_playBehaviour.set(kMODOneShotLoops);
2224 	m_playBehaviour.reset(kMODSampleSwap);
2225 
2226 	return ok;
2227 }
2228 
2229 
2230 #ifndef MODPLUG_NO_FILESAVE
2231 
SaveMod(std::ostream & f) const2232 bool CSoundFile::SaveMod(std::ostream &f) const
2233 {
2234 	if(m_nChannels == 0)
2235 	{
2236 		return false;
2237 	}
2238 
2239 	// Write song title
2240 	{
2241 		char name[20];
2242 		mpt::String::WriteBuf(mpt::String::maybeNullTerminated, name) = m_songName;
2243 		mpt::IO::Write(f, name);
2244 	}
2245 
2246 	std::vector<SmpLength> sampleLength(32, 0);
2247 	std::vector<SAMPLEINDEX> sampleSource(32, 0);
2248 
2249 	if(GetNumInstruments())
2250 	{
2251 		INSTRUMENTINDEX lastIns = std::min(INSTRUMENTINDEX(31), GetNumInstruments());
2252 		for(INSTRUMENTINDEX ins = 1; ins <= lastIns; ins++) if (Instruments[ins])
2253 		{
2254 			// Find some valid sample associated with this instrument.
2255 			for(auto smp : Instruments[ins]->Keyboard)
2256 			{
2257 				if(smp > 0 && smp <= GetNumSamples())
2258 				{
2259 					sampleSource[ins] = smp;
2260 					break;
2261 				}
2262 			}
2263 		}
2264 	} else
2265 	{
2266 		for(SAMPLEINDEX i = 1; i <= 31; i++)
2267 		{
2268 			sampleSource[i] = i;
2269 		}
2270 	}
2271 
2272 	// Write sample headers
2273 	for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
2274 	{
2275 		MODSampleHeader sampleHeader;
2276 		mpt::String::WriteBuf(mpt::String::maybeNullTerminated, sampleHeader.name) = m_szNames[sampleSource[smp]];
2277 		sampleLength[smp] = sampleHeader.ConvertToMOD(sampleSource[smp] <= GetNumSamples() ? GetSample(sampleSource[smp]) : ModSample(MOD_TYPE_MOD));
2278 		mpt::IO::Write(f, sampleHeader);
2279 	}
2280 
2281 	// Write order list
2282 	MODFileHeader fileHeader;
2283 	MemsetZero(fileHeader);
2284 
2285 	PATTERNINDEX writePatterns = 0;
2286 	uint8 writtenOrders = 0;
2287 	for(ORDERINDEX ord = 0; ord < Order().GetLength() && writtenOrders < 128; ord++)
2288 	{
2289 		// Ignore +++ and --- patterns in order list, as well as high patterns (MOD officially only supports up to 128 patterns)
2290 		if(ord == Order().GetRestartPos())
2291 		{
2292 			fileHeader.restartPos = writtenOrders;
2293 		}
2294 		if(Order()[ord] < 128)
2295 		{
2296 			fileHeader.orderList[writtenOrders++] = static_cast<uint8>(Order()[ord]);
2297 			if(writePatterns <= Order()[ord])
2298 			{
2299 				writePatterns = Order()[ord] + 1;
2300 			}
2301 		}
2302 	}
2303 	fileHeader.numOrders = writtenOrders;
2304 	mpt::IO::Write(f, fileHeader);
2305 
2306 	// Write magic bytes
2307 	char modMagic[4];
2308 	CHANNELINDEX writeChannels = std::min(CHANNELINDEX(99), GetNumChannels());
2309 	if(writeChannels == 4)
2310 	{
2311 		// ProTracker may not load files with more than 64 patterns correctly if we do not specify the M!K! magic.
2312 		if(writePatterns <= 64)
2313 			memcpy(modMagic, "M.K.", 4);
2314 		else
2315 			memcpy(modMagic, "M!K!", 4);
2316 	} else if(writeChannels < 10)
2317 	{
2318 		memcpy(modMagic, "0CHN", 4);
2319 		modMagic[0] += static_cast<char>(writeChannels);
2320 	} else
2321 	{
2322 		memcpy(modMagic, "00CH", 4);
2323 		modMagic[0] += static_cast<char>(writeChannels / 10u);
2324 		modMagic[1] += static_cast<char>(writeChannels % 10u);
2325 	}
2326 	mpt::IO::Write(f, modMagic);
2327 
2328 	// Write patterns
2329 	bool invalidInstruments = false;
2330 	std::vector<uint8> events;
2331 	for(PATTERNINDEX pat = 0; pat < writePatterns; pat++)
2332 	{
2333 		if(!Patterns.IsValidPat(pat))
2334 		{
2335 			// Invent empty pattern
2336 			events.assign(writeChannels * 64 * 4, 0);
2337 			mpt::IO::Write(f, events);
2338 			continue;
2339 		}
2340 
2341 		for(ROWINDEX row = 0; row < 64; row++)
2342 		{
2343 			if(row >= Patterns[pat].GetNumRows())
2344 			{
2345 				// Invent empty row
2346 				events.assign(writeChannels * 4, 0);
2347 				mpt::IO::Write(f, events);
2348 				continue;
2349 			}
2350 			PatternRow rowBase = Patterns[pat].GetRow(row);
2351 
2352 			events.resize(writeChannels * 4);
2353 			size_t eventByte = 0;
2354 			for(CHANNELINDEX chn = 0; chn < writeChannels; chn++, eventByte += 4)
2355 			{
2356 				const ModCommand &m = rowBase[chn];
2357 				uint8 command = m.command, param = m.param;
2358 				ModSaveCommand(command, param, false, true);
2359 
2360 				if(m.volcmd == VOLCMD_VOLUME && !command && !param)
2361 				{
2362 					// Maybe we can save some volume commands...
2363 					command = 0x0C;
2364 					param = std::min(m.vol, uint8(64));
2365 				}
2366 
2367 				uint16 period = 0;
2368 				// Convert note to period
2369 				if(m.note >= 24 + NOTE_MIN && m.note < std::size(ProTrackerPeriodTable) + 24 + NOTE_MIN)
2370 				{
2371 					period = ProTrackerPeriodTable[m.note - 24 - NOTE_MIN];
2372 				}
2373 
2374 				const uint8 instr = (m.instr > 31) ? 0 : m.instr;
2375 				if(m.instr > 31)
2376 					invalidInstruments = true;
2377 
2378 				events[eventByte + 0] = ((period >> 8) & 0x0F) | (instr & 0x10);
2379 				events[eventByte + 1] = period & 0xFF;
2380 				events[eventByte + 2] = ((instr & 0x0F) << 4) | (command & 0x0F);
2381 				events[eventByte + 3] = param;
2382 			}
2383 			mpt::IO::WriteRaw(f, mpt::as_span(events));
2384 		}
2385 	}
2386 
2387 	if(invalidInstruments)
2388 	{
2389 		AddToLog(LogWarning, U_("Warning: This track references sample slots higher than 31. Such samples cannot be saved in the MOD format, and thus the notes will not sound correct. Use the Cleanup tool to rearrange and remove unused samples."));
2390 	}
2391 
2392 	//Check for unsaved patterns
2393 	for(PATTERNINDEX pat = writePatterns; pat < Patterns.Size(); pat++)
2394 	{
2395 		if(Patterns.IsValidPat(pat))
2396 		{
2397 			AddToLog(LogWarning, U_("Warning: This track contains at least one pattern after the highest pattern number referred to in the sequence. Such patterns are not saved in the MOD format."));
2398 			break;
2399 		}
2400 	}
2401 
2402 	// Writing samples
2403 	for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
2404 	{
2405 		if(sampleLength[smp] == 0)
2406 		{
2407 			continue;
2408 		}
2409 		const ModSample &sample = Samples[sampleSource[smp]];
2410 
2411 		const mpt::IO::Offset sampleStart = mpt::IO::TellWrite(f);
2412 		const size_t writtenBytes = MODSampleHeader::GetSampleFormat().WriteSample(f, sample, sampleLength[smp]);
2413 
2414 		const int8 silence = 0;
2415 
2416 		// Write padding byte if the sample size is odd.
2417 		if((writtenBytes % 2u) != 0)
2418 		{
2419 			mpt::IO::Write(f, silence);
2420 		}
2421 
2422 		if(!sample.uFlags[CHN_LOOP] && writtenBytes >= 2)
2423 		{
2424 			// First two bytes of oneshot samples have to be 0 due to PT's one-shot loop
2425 			const mpt::IO::Offset sampleEnd = mpt::IO::TellWrite(f);
2426 			mpt::IO::SeekAbsolute(f, sampleStart);
2427 			mpt::IO::Write(f, silence);
2428 			mpt::IO::Write(f, silence);
2429 			mpt::IO::SeekAbsolute(f, sampleEnd);
2430 		}
2431 	}
2432 
2433 	return true;
2434 }
2435 
2436 #endif  // MODPLUG_NO_FILESAVE
2437 
2438 
2439 OPENMPT_NAMESPACE_END
2440