1 /*
2  * This source code is public domain.
3  *
4  * Authors: Olivier Lapicque <olivierl@jps.net>
5 */
6 
7 ///////////////////////////////////////////////////
8 //
9 // AMF module loader
10 //
11 // There is 2 types of AMF files:
12 // - ASYLUM Music Format
13 // - Advanced Music Format(DSM)
14 //
15 ///////////////////////////////////////////////////
16 #include "stdafx.h"
17 #include "sndfile.h"
18 
19 //#define AMFLOG
20 
21 //#pragma warning(disable:4244)
22 
23 #pragma pack(1)
24 
25 typedef struct _AMFFILEHEADER
26 {
27 	UCHAR szAMF[3];
28 	UCHAR version;
29 	CHAR title[32];
30 	UCHAR numsamples;
31 	UCHAR numorders;
32 	USHORT numtracks;
33 	UCHAR numchannels;
34 } AMFFILEHEADER;
35 
36 typedef struct _AMFSAMPLE
37 {
38 	UCHAR type;
39 	CHAR  samplename[32];
40 	CHAR  filename[13];
41 	ULONG offset;
42 	ULONG length;
43 	USHORT c2spd;
44 	UCHAR volume;
45 } AMFSAMPLE;
46 
47 
48 #pragma pack()
49 
50 
51 #ifdef AMFLOG
52 extern void Log(LPCSTR, ...);
53 #endif
54 
AMF_Unpack(MODCOMMAND * pPat,const BYTE * pTrack,UINT nRows,UINT nChannels)55 VOID AMF_Unpack(MODCOMMAND *pPat, const BYTE *pTrack, UINT nRows, UINT nChannels)
56 //-------------------------------------------------------------------------------
57 {
58 	UINT lastinstr = 0;
59 	UINT nTrkSize = bswapLE16(*(USHORT *)pTrack);
60 	nTrkSize += (UINT)pTrack[2] << 16;
61 	pTrack += 3;
62 	while (nTrkSize--)
63 	{
64 		UINT row = pTrack[0];
65 		UINT cmd = pTrack[1];
66 		UINT arg = pTrack[2];
67 		if (row >= nRows) break;
68 		MODCOMMAND *m = pPat + row * nChannels;
69 		if (cmd < 0x7F) // note+vol
70 		{
71 			m->note = cmd+1;
72 			if (!m->instr) m->instr = lastinstr;
73 			m->volcmd = VOLCMD_VOLUME;
74 			m->vol = arg;
75 		} else
76 		if (cmd == 0x7F) // duplicate row
77 		{
78 			signed char rdelta = (signed char)arg;
79 			int rowsrc = (int)row + (int)rdelta;
80 			if ((rowsrc >= 0) && (rowsrc < (int)nRows)) memcpy(m, &pPat[rowsrc*nChannels],sizeof(pPat[rowsrc*nChannels]));
81 		} else
82 		if (cmd == 0x80) // instrument
83 		{
84 			m->instr = arg+1;
85 			lastinstr = m->instr;
86 		} else
87 		if (cmd == 0x83) // volume
88 		{
89 			m->volcmd = VOLCMD_VOLUME;
90 			m->vol = arg;
91 		} else
92 		// effect
93 		{
94 			UINT command = cmd & 0x7F;
95 			UINT param = arg;
96 			switch(command)
97 			{
98 			// 0x01: Set Speed
99 			case 0x01:	command = CMD_SPEED; break;
100 			// 0x02: Volume Slide
101 			// 0x0A: Tone Porta + Vol Slide
102 			// 0x0B: Vibrato + Vol Slide
103 			case 0x02:	command = CMD_VOLUMESLIDE;
104 			case 0x0A:	if (command == 0x0A) command = CMD_TONEPORTAVOL;
105 			case 0x0B:	if (command == 0x0B) command = CMD_VIBRATOVOL;
106 						if (param & 0x80) param = (-(signed char)param)&0x0F;
107 						else param = (param&0x0F)<<4;
108 						break;
109 			// 0x04: Porta Up/Down
110 			case 0x04:	if (param & 0x80) { command = CMD_PORTAMENTOUP; param = (-(signed char)param)&0x7F; }
111 						else { command = CMD_PORTAMENTODOWN; } break;
112 			// 0x06: Tone Portamento
113 			case 0x06:	command = CMD_TONEPORTAMENTO; break;
114 			// 0x07: Tremor
115 			case 0x07:	command = CMD_TREMOR; break;
116 			// 0x08: Arpeggio
117 			case 0x08:	command = CMD_ARPEGGIO; break;
118 			// 0x09: Vibrato
119 			case 0x09:	command = CMD_VIBRATO; break;
120 			// 0x0C: Pattern Break
121 			case 0x0C:	command = CMD_PATTERNBREAK; break;
122 			// 0x0D: Position Jump
123 			case 0x0D:	command = CMD_POSITIONJUMP; break;
124 			// 0x0F: Retrig
125 			case 0x0F:	command = CMD_RETRIG; break;
126 			// 0x10: Offset
127 			case 0x10:	command = CMD_OFFSET; break;
128 			// 0x11: Fine Volume Slide
129 			case 0x11:	if (param) { command = CMD_VOLUMESLIDE;
130 							if (param & 0x80) param = 0xF0|((-(signed char)param)&0x0F);
131 							else param = 0x0F|((param&0x0F)<<4);
132 						} else command = 0; break;
133 			// 0x12: Fine Portamento
134 			// 0x16: Extra Fine Portamento
135 			case 0x12:
136 			case 0x16:	if (param) { int mask = (command == 0x16) ? 0xE0 : 0xF0;
137 							command = (param & 0x80) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN;
138 							if (param & 0x80) param = mask|((-(signed char)param)&0x0F);
139 							else param |= mask;
140 						} else command = 0; break;
141 			// 0x13: Note Delay
142 			case 0x13:	command = CMD_S3MCMDEX; param = 0xD0|(param & 0x0F); break;
143 			// 0x14: Note Cut
144 			case 0x14:	command = CMD_S3MCMDEX; param = 0xC0|(param & 0x0F); break;
145 			// 0x15: Set Tempo
146 			case 0x15:	command = CMD_TEMPO; break;
147 			// 0x17: Panning
148 			case 0x17:	param = (param+64)&0x7F;
149 						if (m->command) { if (!m->volcmd) { m->volcmd = VOLCMD_PANNING;  m->vol = param/2; } command = 0; }
150 						else { command = CMD_PANNING8; }
151 				break;
152 			// Unknown effects
153 			default:	command = param = 0;
154 			}
155 			if (command)
156 			{
157 				m->command = command;
158 				m->param = param;
159 			}
160 		}
161 		pTrack += 3;
162 	}
163 }
164 
165 
166 
ReadAMF(LPCBYTE lpStream,const DWORD dwMemLength)167 BOOL CSoundFile::ReadAMF(LPCBYTE lpStream, const DWORD dwMemLength)
168 //-----------------------------------------------------------
169 {
170 	const AMFFILEHEADER *pfh = (AMFFILEHEADER *)lpStream;
171 	DWORD dwMemPos;
172 
173 	if ((!lpStream) || (dwMemLength < 2048)) return FALSE;
174 	if ((!strncmp((LPCTSTR)lpStream, "ASYLUM Music Format V1.0", 25)) && (dwMemLength > 4096))
175 	{
176 		UINT numorders, numpats, numsamples;
177 
178 		dwMemPos = 32;
179 		numpats = lpStream[dwMemPos+3];
180 		numorders = lpStream[dwMemPos+4];
181 		numsamples = 64;
182 		dwMemPos += 6;
183 		if ((!numpats) || (numpats > MAX_PATTERNS) || (!numorders)
184 		 || (numpats*64*32 + 294 + 37*64 >= dwMemLength)) return FALSE;
185 		m_nType = MOD_TYPE_AMF0;
186 		m_nChannels = 8;
187 		m_nInstruments = 0;
188 		m_nSamples = 31;
189 		m_nDefaultTempo = 125;
190 		m_nDefaultSpeed = 6;
191 		for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
192 		{
193 			Order[iOrd] = (iOrd < numorders) ? lpStream[dwMemPos+iOrd] : 0xFF;
194 		}
195 		dwMemPos = 294; // ???
196 		for (UINT iSmp=0; iSmp<numsamples; iSmp++)
197 		{
198 			MODINSTRUMENT *psmp = &Ins[iSmp+1];
199 			memcpy(m_szNames[iSmp+1], lpStream+dwMemPos, 22);
200 			m_szNames[iSmp+1][21] = '\0';
201 			psmp->nFineTune = MOD2XMFineTune(lpStream[dwMemPos+22]);
202 			psmp->nVolume = lpStream[dwMemPos+23];
203 			psmp->nGlobalVol = 64;
204 			if (psmp->nVolume > 0x40) psmp->nVolume = 0x40;
205 			psmp->nVolume <<= 2;
206 			psmp->nLength = bswapLE32(*((LPDWORD)(lpStream+dwMemPos+25)));
207 			psmp->nLoopStart = bswapLE32(*((LPDWORD)(lpStream+dwMemPos+29)));
208 			psmp->nLoopEnd = psmp->nLoopStart + bswapLE32(*((LPDWORD)(lpStream+dwMemPos+33)));
209 			if ((psmp->nLoopEnd > psmp->nLoopStart) && (psmp->nLoopEnd <= psmp->nLength))
210 			{
211 				psmp->uFlags = CHN_LOOP;
212 			} else
213 			{
214 				psmp->nLoopStart = psmp->nLoopEnd = 0;
215 			}
216 			if ((psmp->nLength) && (iSmp>31)) m_nSamples = iSmp+1;
217 			dwMemPos += 37;
218 		}
219 		for (UINT iPat=0; iPat<numpats; iPat++)
220 		{
221 			MODCOMMAND *p = AllocatePattern(64, m_nChannels);
222 			if (!p) break;
223 			Patterns[iPat] = p;
224 			PatternSize[iPat] = 64;
225 			const UCHAR *pin = lpStream + dwMemPos;
226 			for (UINT i=0; i<8*64; i++)
227 			{
228 				p->note = 0;
229 
230 				if (pin[0])
231 				{
232 					p->note = pin[0] + 13;
233 				}
234 				p->instr = pin[1];
235 				p->command = pin[2];
236 				p->param = pin[3];
237 				if (p->command > 0x0F)
238 				{
239 				#ifdef AMFLOG
240 					Log("0x%02X.0x%02X ?", p->command, p->param);
241 				#endif
242 					p->command = 0;
243 				}
244 				ConvertModCommand(p);
245 				pin += 4;
246 				p++;
247 			}
248 			dwMemPos += 64*32;
249 		}
250 		// Read samples
251 		for (UINT iData=0; iData<m_nSamples; iData++)
252 		{
253 			MODINSTRUMENT *psmp = &Ins[iData+1];
254 			if (psmp->nLength)
255 			{
256 				if (dwMemPos > dwMemLength) return FALSE;
257 				dwMemPos += ReadSample(psmp, RS_PCM8S, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
258 			}
259 		}
260 		return TRUE;
261 	}
262 	////////////////////////////
263 	// DSM/AMF
264 	USHORT *ptracks[MAX_PATTERNS];
265 	DWORD sampleseekpos[MAX_SAMPLES];
266 
267 	if ((pfh->szAMF[0] != 'A') || (pfh->szAMF[1] != 'M') || (pfh->szAMF[2] != 'F')
268 	 || (pfh->version < 10) || (pfh->version > 14) || (!bswapLE16(pfh->numtracks))
269 	 || (!pfh->numorders) || (pfh->numorders > MAX_PATTERNS)
270 	 || (!pfh->numsamples) || (pfh->numsamples >= MAX_SAMPLES)
271 	 || (pfh->numchannels < 4) || (pfh->numchannels > 32))
272 		return FALSE;
273 	memcpy(m_szNames[0], pfh->title, 32);
274 	m_szNames[0][31] = '\0';
275 	dwMemPos = sizeof(AMFFILEHEADER);
276 	m_nType = MOD_TYPE_AMF;
277 	m_nChannels = pfh->numchannels;
278 	m_nSamples = pfh->numsamples;
279 	m_nInstruments = 0;
280 	// Setup Channel Pan Positions
281 	if (pfh->version >= 11)
282 	{
283 		signed char *panpos = (signed char *)(lpStream + dwMemPos);
284 		UINT nchannels = (pfh->version >= 13) ? 32 : 16;
285 		for (UINT i=0; i<nchannels; i++)
286 		{
287 			int pan = (panpos[i] + 64) * 2;
288 			if (pan < 0) pan = 0;
289 			if (pan > 256) { pan = 128; ChnSettings[i].dwFlags |= CHN_SURROUND; }
290 			ChnSettings[i].nPan = pan;
291 		}
292 		dwMemPos += nchannels;
293 	} else
294 	{
295 		for (UINT i=0; i<16; i++)
296 		{
297 			ChnSettings[i].nPan = (lpStream[dwMemPos+i] & 1) ? 0x30 : 0xD0;
298 		}
299 		dwMemPos += 16;
300 	}
301 	// Get Tempo/Speed
302 	m_nDefaultTempo = 125;
303 	m_nDefaultSpeed = 6;
304 	if (pfh->version >= 13)
305 	{
306 		if (lpStream[dwMemPos] >= 32) m_nDefaultTempo = lpStream[dwMemPos];
307 		if (lpStream[dwMemPos+1] <= 32) m_nDefaultSpeed = lpStream[dwMemPos+1];
308 		dwMemPos += 2;
309 	}
310 	// Setup sequence list
311 	for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
312 	{
313 		Order[iOrd] = 0xFF;
314 		if (iOrd < pfh->numorders)
315 		{
316 			Order[iOrd] = iOrd;
317 			PatternSize[iOrd] = 64;
318 			if (pfh->version >= 14)
319 			{
320 				PatternSize[iOrd] = bswapLE16(*(USHORT *)(lpStream+dwMemPos));
321 				dwMemPos += 2;
322 			}
323 			ptracks[iOrd] = (USHORT *)(lpStream+dwMemPos);
324 			dwMemPos += m_nChannels * sizeof(USHORT);
325 		}
326 	}
327 	if (dwMemPos + m_nSamples * (sizeof(AMFSAMPLE)+8) > dwMemLength) return TRUE;
328 	// Read Samples
329 	UINT maxsampleseekpos = 0;
330 	for (UINT iIns=0; iIns<m_nSamples; iIns++)
331 	{
332 		MODINSTRUMENT *pins = &Ins[iIns+1];
333 		const AMFSAMPLE *psh = (AMFSAMPLE *)(lpStream + dwMemPos);
334 
335 		dwMemPos += sizeof(AMFSAMPLE);
336 		memcpy(m_szNames[iIns+1], psh->samplename, 32);
337 		m_szNames[iIns+1][31] = '\0';
338 		memcpy(pins->name, psh->filename, 13);
339 		pins->name[12] = '\0';
340 		pins->nLength = bswapLE32(psh->length);
341 		pins->nC4Speed = bswapLE16(psh->c2spd);
342 		pins->nGlobalVol = 64;
343 		pins->nVolume = psh->volume * 4;
344 		if (pfh->version >= 11)
345 		{
346 			pins->nLoopStart = bswapLE32(*(DWORD *)(lpStream+dwMemPos));
347 			pins->nLoopEnd = bswapLE32(*(DWORD *)(lpStream+dwMemPos+4));
348 			dwMemPos += 8;
349 		} else
350 		{
351 			pins->nLoopStart = bswapLE16(*(WORD *)(lpStream+dwMemPos));
352 			pins->nLoopEnd = pins->nLength;
353 			dwMemPos += 2;
354 		}
355 		sampleseekpos[iIns] = 0;
356 		if ((psh->type) && (bswapLE32(psh->offset) < dwMemLength-1))
357 		{
358 			sampleseekpos[iIns] = bswapLE32(psh->offset);
359 			if (bswapLE32(psh->offset) > maxsampleseekpos)
360 				maxsampleseekpos = bswapLE32(psh->offset);
361 			if ((pins->nLoopEnd > pins->nLoopStart + 2)
362 			 && (pins->nLoopEnd <= pins->nLength)) pins->uFlags |= CHN_LOOP;
363 		}
364 	}
365 	// Read Track Mapping Table
366 	USHORT *pTrackMap = (USHORT *)(lpStream+dwMemPos);
367 	UINT realtrackcnt = 0;
368 	dwMemPos += pfh->numtracks * sizeof(USHORT);
369 	if (dwMemPos >= dwMemLength)
370 		return TRUE;
371 
372 	for (UINT iTrkMap=0; iTrkMap<pfh->numtracks; iTrkMap++)
373 	{
374 		if (realtrackcnt < pTrackMap[iTrkMap]) realtrackcnt = pTrackMap[iTrkMap];
375 	}
376 	// Store tracks positions
377 	BYTE **pTrackData = new BYTE *[realtrackcnt];
378 	memset(pTrackData, 0, sizeof(BYTE *) * realtrackcnt);
379 	for (UINT iTrack=0; iTrack<realtrackcnt; iTrack++) if (dwMemPos <= dwMemLength - 3)
380 	{
381 		UINT nTrkSize = bswapLE16(*(USHORT *)(lpStream+dwMemPos));
382 		nTrkSize += (UINT)lpStream[dwMemPos+2] << 16;
383 		if (dwMemPos + nTrkSize * 3 + 3 <= dwMemLength)
384 		{
385 			pTrackData[iTrack] = (BYTE *)(lpStream + dwMemPos);
386 		}
387 		dwMemPos += nTrkSize * 3 + 3;
388 	}
389 	// Create the patterns from the list of tracks
390 	for (UINT iPat=0; iPat<pfh->numorders; iPat++)
391 	{
392 		MODCOMMAND *p = AllocatePattern(PatternSize[iPat], m_nChannels);
393 		if (!p) break;
394 		Patterns[iPat] = p;
395 		for (UINT iChn=0; iChn<m_nChannels; iChn++)
396 		{
397 			UINT nTrack = bswapLE16(ptracks[iPat][iChn]);
398 			if ((nTrack) && (nTrack <= pfh->numtracks))
399 			{
400 				UINT realtrk = bswapLE16(pTrackMap[nTrack-1]);
401 				if (realtrk)
402 				{
403 					realtrk--;
404 					if ((realtrk < realtrackcnt) && (pTrackData[realtrk]))
405 					{
406 						AMF_Unpack(p+iChn, pTrackData[realtrk], PatternSize[iPat], m_nChannels);
407 					}
408 				}
409 			}
410 		}
411 	}
412 	delete[] pTrackData;
413 	// Read Sample Data
414 	for (UINT iSeek=1; iSeek<=maxsampleseekpos; iSeek++)
415 	{
416 		if (dwMemPos >= dwMemLength) break;
417 		for (UINT iSmp=0; iSmp<m_nSamples; iSmp++) if (iSeek == sampleseekpos[iSmp])
418 		{
419 			MODINSTRUMENT *pins = &Ins[iSmp+1];
420 			dwMemPos += ReadSample(pins, RS_PCM8U, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
421 			break;
422 		}
423 	}
424 	return TRUE;
425 }
426