1 /*
2  * ITTools.h
3  * ---------
4  * Purpose: Definition of IT file structures and helper functions
5  * Notes  : (currently none)
6  * Authors: OpenMPT Devs
7  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
8  */
9 
10 
11 #pragma once
12 
13 #include "openmpt/all/BuildSettings.hpp"
14 
15 #include "../soundlib/ModInstrument.h"
16 #include "../soundlib/ModSample.h"
17 #include "../soundlib/SampleIO.h"
18 
19 OPENMPT_NAMESPACE_BEGIN
20 
21 struct ITFileHeader
22 {
23 	// Header Flags
24 	enum ITHeaderFlags
25 	{
26 		useStereoPlayback		= 0x01,
27 		vol0Optimisations		= 0x02,
28 		instrumentMode			= 0x04,
29 		linearSlides			= 0x08,
30 		itOldEffects			= 0x10,
31 		itCompatGxx				= 0x20,
32 		useMIDIPitchController	= 0x40,
33 		reqEmbeddedMIDIConfig	= 0x80,
34 		extendedFilterRange		= 0x1000,
35 	};
36 
37 	// Special Flags
38 	enum ITHeaderSpecialFlags
39 	{
40 		embedSongMessage		= 0x01,
41 		embedEditHistory		= 0x02,
42 		embedPatternHighlights	= 0x04,
43 		embedMIDIConfiguration	= 0x08,
44 	};
45 
46 	char     id[4];				// Magic Bytes (IMPM)
47 	char     songname[26];		// Song Name, null-terminated (but may also contain nulls)
48 	uint8le  highlight_minor;	// Rows per Beat highlight
49 	uint8le  highlight_major;	// Rows per Measure highlight
50 	uint16le ordnum;			// Number of Orders
51 	uint16le insnum;			// Number of Instruments
52 	uint16le smpnum;			// Number of Samples
53 	uint16le patnum;			// Number of Patterns
54 	uint16le cwtv;				// "Made With" Tracker
55 	uint16le cmwt;				// "Compatible With" Tracker
56 	uint16le flags;				// Header Flags
57 	uint16le special;			// Special Flags, for embedding extra information
58 	uint8le  globalvol;			// Global Volume (0...128)
59 	uint8le  mv;				// Master Volume (0...128), referred to as Sample Volume in OpenMPT
60 	uint8le  speed;				// Initial Speed (1...255)
61 	uint8le  tempo;				// Initial Tempo (31...255)
62 	uint8le  sep;				// Pan Separation (0...128)
63 	uint8le  pwd;				// Pitch Wheel Depth
64 	uint16le msglength;			// Length of Song Message
65 	uint32le msgoffset;			// Offset of Song Message in File (IT crops message after first null)
66 	uint32le reserved;			// Some IT versions save an edit timer here. ChibiTracker writes "CHBI" here. OpenMPT and Schism Tracker save extended version information here.
67 	uint8le  chnpan[64];		// Initial Channel Panning
68 	uint8le  chnvol[64];		// Initial Channel Volume
69 };
70 
71 MPT_BINARY_STRUCT(ITFileHeader, 192)
72 
73 
74 struct ITEnvelope
75 {
76 	// Envelope Flags
77 	enum ITEnvelopeFlags
78 	{
79 		envEnabled	= 0x01,
80 		envLoop		= 0x02,
81 		envSustain	= 0x04,
82 		envCarry	= 0x08,
83 		envFilter	= 0x80,
84 	};
85 
86 	struct Node
87 	{
88 		int8le   value;
89 		uint16le tick;
90 	};
91 
92 	uint8 flags;	// Envelope Flags
93 	uint8 num;		// Number of Envelope Nodes
94 	uint8 lpb;		// Loop Start
95 	uint8 lpe;		// Loop End
96 	uint8 slb;		// Sustain Start
97 	uint8 sle;		// Sustain End
98 	Node  data[25];	// Envelope Node Positions / Values
99 	uint8 reserved;	// Reserved
100 
101 	// Convert OpenMPT's internal envelope format to an IT/MPTM envelope.
102 	void ConvertToIT(const InstrumentEnvelope &mptEnv, uint8 envOffset, uint8 envDefault);
103 	// Convert IT/MPTM envelope data into OpenMPT's internal envelope format - To be used by ITInstrToMPT()
104 	void ConvertToMPT(InstrumentEnvelope &mptEnv, uint8 envOffset, uint8 maxNodes) const;
105 };
106 
107 MPT_BINARY_STRUCT(ITEnvelope::Node, 3)
108 MPT_BINARY_STRUCT(ITEnvelope, 82)
109 
110 
111 // Old Impulse Instrument Format (cmwt < 0x200)
112 struct ITOldInstrument
113 {
114 	enum ITOldInstrFlags
115 	{
116 		envEnabled	= 0x01,
117 		envLoop		= 0x02,
118 		envSustain	= 0x04,
119 	};
120 
121 	char     id[4];			// Magic Bytes (IMPI)
122 	char     filename[13];	// DOS Filename, null-terminated
123 	uint8le  flags;			// Volume Envelope Flags
124 	uint8le  vls;			// Envelope Loop Start
125 	uint8le  vle;			// Envelope Loop End
126 	uint8le  sls;			// Envelope Sustain Start
127 	uint8le  sle;			// Envelope Sustain End
128 	char     reserved1[2];	// Reserved
129 	uint16le fadeout;		// Instrument Fadeout (0...128)
130 	uint8le  nna;			// New Note Action
131 	uint8le  dnc;			// Duplicate Note Check Type
132 	uint16le trkvers;		// Tracker ID
133 	uint8le  nos;			// Number of embedded samples
134 	char     reserved2;		// Reserved
135 	char     name[26];		// Instrument Name, null-terminated (but may also contain nulls)
136 	char     reserved3[6];	// Even more reserved bytes
137 	uint8le  keyboard[240];	// Sample / Transpose map
138 	uint8le  volenv[200];	// This appears to be a pre-computed (interpolated) version of the volume envelope data found below.
139 	uint8le  nodes[25 * 2];	// Volume Envelope Node Positions / Values
140 
141 	// Convert an ITOldInstrument to OpenMPT's internal instrument representation.
142 	void ConvertToMPT(ModInstrument &mptIns) const;
143 };
144 
145 MPT_BINARY_STRUCT(ITOldInstrument, 554)
146 
147 
148 // Impulse Instrument Format
149 struct ITInstrument
150 {
151 	enum ITInstrumentFlags
152 	{
153 		ignorePanning	= 0x80,
154 		enableCutoff	= 0x80,
155 		enableResonance	= 0x80,
156 	};
157 
158 	char     id[4];			// Magic Bytes (IMPI)
159 	char     filename[13];	// DOS Filename, null-terminated
160 	uint8le  nna;			// New Note Action
161 	uint8le  dct;			// Duplicate Note Check Type
162 	uint8le  dca;			// Duplicate Note Check Action
163 	uint16le fadeout;		// Instrument Fadeout (0...256, although values up to 1024 would be sensible. Up to IT2.07, the limit was 0...128)
164 	int8le   pps;			// Pitch/Pan Separatation
165 	uint8le  ppc;			// Pitch/Pan Centre
166 	uint8le  gbv;			// Global Volume
167 	uint8le  dfp;			// Panning
168 	uint8le  rv;			// Vol Swing
169 	uint8le  rp;			// Pan Swing
170 	uint16le trkvers;		// Tracker ID
171 	uint8le  nos;			// Number of embedded samples
172 	char     reserved1;		// Reserved
173 	char     name[26];		// Instrument Name, null-terminated (but may also contain nulls)
174 	uint8le  ifc;			// Filter Cutoff
175 	uint8le  ifr;			// Filter Resonance
176 	uint8le  mch;			// MIDI Channel
177 	uint8le  mpr;			// MIDI Program
178 	uint8le  mbank[2];		// MIDI Bank
179 	uint8le  keyboard[240];	// Sample / Transpose map
180 	ITEnvelope volenv;		// Volume Envelope
181 	ITEnvelope panenv;		// Pan Envelope
182 	ITEnvelope pitchenv;	// Pitch / Filter Envelope
183 	char       dummy[4];	// IT saves some additional padding bytes to match the size of the old instrument format for simplified loading. We use them for some hacks.
184 
185 	// Convert OpenMPT's internal instrument representation to an ITInstrument. Returns amount of bytes that need to be written.
186 	uint32 ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile);
187 	// Convert an ITInstrument to OpenMPT's internal instrument representation. Returns size of the instrument data that has been read.
188 	uint32 ConvertToMPT(ModInstrument &mptIns, MODTYPE fromType) const;
189 };
190 
191 MPT_BINARY_STRUCT(ITInstrument, 554)
192 
193 
194 // MPT IT Instrument Extension
195 struct ITInstrumentEx
196 {
197 	ITInstrument iti;		// Normal IT Instrument
198 	uint8 keyboardhi[120];	// High Byte of Sample map
199 
200 	// Convert OpenMPT's internal instrument representation to an ITInstrumentEx. Returns amount of bytes that need to be written.
201 	uint32 ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile);
202 	// Convert an ITInstrumentEx to OpenMPT's internal instrument representation. Returns size of the instrument data that has been read.
203 	uint32 ConvertToMPT(ModInstrument &mptIns, MODTYPE fromType) const;
204 };
205 
206 MPT_BINARY_STRUCT(ITInstrumentEx, sizeof(ITInstrument) + 120)
207 
208 
209 // IT Sample Format
210 struct ITSample
211 {
212 	// Magic Bytes
213 	enum Magic
214 	{
215 		magic = 0x53504D49,	// "IMPS" IT Sample Header Magic Bytes
216 	};
217 
218 	enum ITSampleFlags
219 	{
220 		sampleDataPresent	= 0x01,
221 		sample16Bit			= 0x02,
222 		sampleStereo		= 0x04,
223 		sampleCompressed	= 0x08,
224 		sampleLoop			= 0x10,
225 		sampleSustain		= 0x20,
226 		sampleBidiLoop		= 0x40,
227 		sampleBidiSustain	= 0x80,
228 
229 		enablePanning		= 0x80,
230 
231 		cvtSignedSample		= 0x01,
232 		cvtOPLInstrument	= 0x40,		// FM instrument in MPTM
233 		cvtExternalSample	= 0x80,		// Keep MPTM sample on disk
234 		cvtADPCMSample		= 0xFF,		// MODPlugin :(
235 
236 		// ITTECH.TXT says these convert flags are "safe to ignore". IT doesn't ignore them, though, so why should we? :)
237 		cvtBigEndian		= 0x02,
238 		cvtDelta			= 0x04,
239 		cvtPTM8to16			= 0x08,
240 	};
241 
242 	char     id[4];			// Magic Bytes (IMPS)
243 	char     filename[13];	// DOS Filename, null-terminated
244 	uint8le  gvl;			// Global Volume
245 	uint8le  flags;			// Sample Flags
246 	uint8le  vol;			// Default Volume
247 	char     name[26];		// Sample Name, null-terminated (but may also contain nulls)
248 	uint8le  cvt;			// Sample Import Format
249 	uint8le  dfp;			// Sample Panning
250 	uint32le length;		// Sample Length (in samples)
251 	uint32le loopbegin;		// Sample Loop Begin (in samples)
252 	uint32le loopend;		// Sample Loop End (in samples)
253 	uint32le C5Speed;		// C-5 frequency
254 	uint32le susloopbegin;	// Sample Sustain Begin (in samples)
255 	uint32le susloopend;	// Sample Sustain End (in samples)
256 	uint32le samplepointer;	// Pointer to sample data
257 	uint8le  vis;			// Auto-Vibrato Rate (called Sweep in IT)
258 	uint8le  vid;			// Auto-Vibrato Depth
259 	uint8le  vir;			// Auto-Vibrato Sweep (called Rate in IT)
260 	uint8le  vit;			// Auto-Vibrato Type
261 
262 	// Convert OpenMPT's internal sample representation to an ITSample.
263 	void ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compress, bool compressIT215, bool allowExternal);
264 	// Convert an ITSample to OpenMPT's internal sample representation.
265 	uint32 ConvertToMPT(ModSample &mptSmp) const;
266 	// Retrieve the internal sample format flags for this instrument.
267 	SampleIO GetSampleFormat(uint16 cwtv = 0x214) const;
268 };
269 
270 MPT_BINARY_STRUCT(ITSample, 80)
271 
272 
273 struct FileHistory;
274 
275 // IT Header extension: Save history
276 struct ITHistoryStruct
277 {
278 	uint16le fatdate;  // DOS / FAT date when the file was opened / created in the editor. For details, read https://docs.microsoft.com/de-de/windows/win32/api/winbase/nf-winbase-dosdatetimetofiletime
279 	uint16le fattime;  // DOS / FAT time when the file was opened / created in the editor.
280 	uint32le runtime;  // The time how long the file was open in the editor, in 1/18.2th seconds. (= ticks of the DOS timer)
281 
282 	// Convert an ITHistoryStruct to OpenMPT's internal edit history representation
283 	void ConvertToMPT(FileHistory &mptHistory) const;
284 	// Convert OpenMPT's internal edit history representation to an ITHistoryStruct
285 	void ConvertToIT(const FileHistory &mptHistory);
286 
287 };
288 
289 MPT_BINARY_STRUCT(ITHistoryStruct, 8)
290 
291 
292 enum IT_ReaderBitMasks
293 {
294 	// pattern row parsing, the channel data is read to obtain
295 	// number of channels active in the pattern. These bit masks are
296 	// to blank out sections of the byte of data being read.
297 
298 	IT_bitmask_patternChanField_c   = 0x7f,
299 	IT_bitmask_patternChanMask_c    = 0x3f,
300 	IT_bitmask_patternChanEnabled_c = 0x80,
301 	IT_bitmask_patternChanUsed_c    = 0x0f
302 };
303 
304 
305 // Calculate Schism Tracker version field for IT / S3M header based on specified release date
306 // Date calculation derived from https://alcor.concordia.ca/~gpkatch/gdate-algorithm.html
307 template<int32 y, int32 m, int32 d>
308 struct SchismVersionFromDate
309 {
310 private:
311 	static constexpr int32 mm = (m + 9) % 12;
312 	static constexpr int32 yy = y - mm / 10;
313 
314 public:
315 	static constexpr int32 date = yy * 365 + yy / 4 - yy / 100 + yy / 400 + (mm * 306 + 5) / 10 + (d - 1);
316 };
317 
318 inline constexpr int32 SchismTrackerEpoch = SchismVersionFromDate<2009, 10, 31>::date;
319 
320 
321 uint32 DecodeITEditTimer(uint16 cwtv, uint32 editTime);
322 
323 OPENMPT_NAMESPACE_END
324