1 /*
2  * This source code is public domain.
3  *
4  * Authors: Olivier Lapicque <olivierl@jps.net>
5 */
6 
7 //////////////////////////////////////////////
8 // AMS module loader                        //
9 //////////////////////////////////////////////
10 #include "stdafx.h"
11 #include "sndfile.h"
12 
13 //#pragma warning(disable:4244)
14 
15 #pragma pack(1)
16 
17 typedef struct AMSFILEHEADER
18 {
19 	char szHeader[7];	// "Extreme"   // changed from CHAR
20 	BYTE verlo, verhi;	// 0x??,0x01
21 	BYTE chncfg;
22 	BYTE samples;
23 	WORD patterns;
24 	WORD orders;
25 	BYTE vmidi;
26 	WORD extra;
27 } AMSFILEHEADER;
28 
29 typedef struct AMSSAMPLEHEADER
30 {
31 	DWORD length;
32 	DWORD loopstart;
33 	DWORD loopend;
34 	BYTE finetune_and_pan;
35 	WORD samplerate;	// C-2 = 8363
36 	BYTE volume;		// 0-127
37 	BYTE infobyte;
38 } AMSSAMPLEHEADER;
39 
40 
41 #pragma pack()
42 
43 
44 
ReadAMS(LPCBYTE lpStream,DWORD dwMemLength)45 BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
46 //-----------------------------------------------------------
47 {
48 	BYTE pkinf[MAX_SAMPLES];
49 	AMSFILEHEADER *pfh = (AMSFILEHEADER *)lpStream;
50 	DWORD dwMemPos;
51 	UINT tmp, tmp2;
52 
53 	if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
54 	if ((pfh->verhi != 0x01) || (strncmp(pfh->szHeader, "Extreme", 7))
55 	 || (!pfh->patterns) || (!pfh->orders) || (!pfh->samples) || (pfh->samples >= MAX_SAMPLES)
56 	 || (pfh->patterns > MAX_PATTERNS) || (pfh->orders > MAX_ORDERS))
57 	{
58 		return ReadAMS2(lpStream, dwMemLength);
59 	}
60 	dwMemPos = sizeof(AMSFILEHEADER) + pfh->extra;
61 	if (dwMemPos + pfh->samples * sizeof(AMSSAMPLEHEADER) + 256 >= dwMemLength) return FALSE;
62 	m_nType = MOD_TYPE_AMS;
63 	m_nInstruments = 0;
64 	m_nChannels = (pfh->chncfg & 0x1F) + 1;
65 	m_nSamples = pfh->samples;
66 	for (UINT nSmp=1; nSmp<=m_nSamples; nSmp++, dwMemPos += sizeof(AMSSAMPLEHEADER))
67 	{
68 		AMSSAMPLEHEADER *psh = (AMSSAMPLEHEADER *)(lpStream + dwMemPos);
69 		MODINSTRUMENT *pins = &Ins[nSmp];
70 		pins->nLength = psh->length;
71 		pins->nLoopStart = psh->loopstart;
72 		pins->nLoopEnd = psh->loopend;
73 		pins->nGlobalVol = 64;
74 		pins->nVolume = psh->volume << 1;
75 		pins->nC4Speed = psh->samplerate;
76 		pins->nPan = (psh->finetune_and_pan & 0xF0);
77 		if (pins->nPan < 0x80) pins->nPan += 0x10;
78 		pins->nFineTune = MOD2XMFineTune(psh->finetune_and_pan & 0x0F);
79 		pins->uFlags = (psh->infobyte & 0x80) ? CHN_16BIT : 0;
80 		if ((pins->nLoopEnd <= pins->nLength) && (pins->nLoopStart+4 <= pins->nLoopEnd)) pins->uFlags |= CHN_LOOP;
81 		pkinf[nSmp] = psh->infobyte;
82 	}
83 	// Read Song Name
84 	tmp = lpStream[dwMemPos++];
85 	if (dwMemPos + tmp + 1 >= dwMemLength) return TRUE;
86 	tmp2 = (tmp < 32) ? tmp : 31;
87 	if (tmp2) memcpy(m_szNames[0], lpStream+dwMemPos, tmp2);
88 	m_szNames[0][tmp2] = 0;
89 	dwMemPos += tmp;
90 	// Read sample names
91 	for (UINT sNam=1; sNam<=m_nSamples; sNam++)
92 	{
93 		if (dwMemPos + 32 >= dwMemLength) return TRUE;
94 		tmp = lpStream[dwMemPos++];
95 		tmp2 = (tmp < 32) ? tmp : 31;
96 		if (tmp2) memcpy(m_szNames[sNam], lpStream+dwMemPos, tmp2);
97 		dwMemPos += tmp;
98 	}
99 	// Skip Channel names
100 	for (UINT cNam=0; cNam<m_nChannels; cNam++)
101 	{
102 		if (dwMemPos + 32 >= dwMemLength) return TRUE;
103 		tmp = lpStream[dwMemPos++];
104 		dwMemPos += tmp;
105 	}
106 	// Read Pattern Names
107 	m_lpszPatternNames = new char[pfh->patterns * 32];  // changed from CHAR
108 	if (!m_lpszPatternNames) return TRUE;
109 	m_nPatternNames = pfh->patterns;
110 	memset(m_lpszPatternNames, 0, m_nPatternNames * 32);
111 	for (UINT pNam=0; pNam < m_nPatternNames; pNam++)
112 	{
113 		if (dwMemPos + 32 >= dwMemLength) return TRUE;
114 		tmp = lpStream[dwMemPos++];
115 		tmp2 = (tmp < 32) ? tmp : 31;
116 		if (tmp2) memcpy(m_lpszPatternNames+pNam*32, lpStream+dwMemPos, tmp2);
117 		dwMemPos += tmp;
118 	}
119 	// Read Song Comments
120 	tmp = *((WORD *)(lpStream+dwMemPos));
121 	dwMemPos += 2;
122 	if (dwMemPos + tmp >= dwMemLength) return TRUE;
123 	if (tmp)
124 	{
125 		m_lpszSongComments = new char[tmp+1];  // changed from CHAR
126 		if (!m_lpszSongComments) return TRUE;
127 		memset(m_lpszSongComments, 0, tmp+1);
128 		memcpy(m_lpszSongComments, lpStream + dwMemPos, tmp);
129 		dwMemPos += tmp;
130 	}
131 	// Read Order List
132 	for (UINT iOrd=0; iOrd<pfh->orders; iOrd++, dwMemPos += 2)
133 	{
134 		UINT n = *((WORD *)(lpStream+dwMemPos));
135 		Order[iOrd] = (BYTE)n;
136 	}
137 	// Read Patterns
138 	for (UINT iPat=0; iPat<pfh->patterns; iPat++)
139 	{
140 		if (dwMemPos + 4 >= dwMemLength) return TRUE;
141 		UINT len = *((DWORD *)(lpStream + dwMemPos));
142 		dwMemPos += 4;
143 		if ((len >= dwMemLength) || (dwMemPos + len > dwMemLength)) return TRUE;
144 		PatternSize[iPat] = 64;
145 		MODCOMMAND *m = AllocatePattern(PatternSize[iPat], m_nChannels);
146 		if (!m) return TRUE;
147 		Patterns[iPat] = m;
148 		const BYTE *p = lpStream + dwMemPos;
149 		UINT row = 0, i = 0;
150 		while ((row < PatternSize[iPat]) && (i+2 < len))
151 		{
152 			BYTE b0 = p[i++];
153 			BYTE b1 = p[i++];
154 			BYTE b2 = 0;
155 			UINT ch = b0 & 0x3F;
156 			// Note+Instr
157 			if (!(b0 & 0x40))
158 			{
159 				b2 = p[i++];
160 				if (ch < m_nChannels)
161 				{
162 					if (b1 & 0x7F) m[ch].note = (b1 & 0x7F) + 25;
163 					m[ch].instr = b2;
164 				}
165 				if (b1 & 0x80)
166 				{
167 					b0 |= 0x40;
168 					b1 = p[i++];
169 				}
170 			}
171 			// Effect
172 			if (b0 & 0x40)
173 			{
174 			anothercommand:
175 				if (b1 & 0x40)
176 				{
177 					if (ch < m_nChannels)
178 					{
179 						m[ch].volcmd = VOLCMD_VOLUME;
180 						m[ch].vol = b1 & 0x3F;
181 					}
182 				} else
183 				{
184 					b2 = p[i++];
185 					if (ch < m_nChannels)
186 					{
187 						UINT cmd = b1 & 0x3F;
188 						if (cmd == 0x0C)
189 						{
190 							m[ch].volcmd = VOLCMD_VOLUME;
191 							m[ch].vol = b2 >> 1;
192 						} else
193 						if (cmd == 0x0E)
194 						{
195 							if (!m[ch].command)
196 							{
197 								UINT command = CMD_S3MCMDEX;
198 								UINT param = b2;
199 								switch(param & 0xF0)
200 								{
201 								case 0x00:	if (param & 0x08) { param &= 0x07; param |= 0x90; } else {command=param=0;} break;
202 								case 0x10:	command = CMD_PORTAMENTOUP; param |= 0xF0; break;
203 								case 0x20:	command = CMD_PORTAMENTODOWN; param |= 0xF0; break;
204 								case 0x30:	param = (param & 0x0F) | 0x10; break;
205 								case 0x40:	param = (param & 0x0F) | 0x30; break;
206 								case 0x50:	param = (param & 0x0F) | 0x20; break;
207 								case 0x60:	param = (param & 0x0F) | 0xB0; break;
208 								case 0x70:	param = (param & 0x0F) | 0x40; break;
209 								case 0x90:	command = CMD_RETRIG; param &= 0x0F; break;
210 								case 0xA0:	if (param & 0x0F) { command = CMD_VOLUMESLIDE; param = (param << 4) | 0x0F; } else command=param=0; break;
211 								case 0xB0:	if (param & 0x0F) { command = CMD_VOLUMESLIDE; param |= 0xF0; } else command=param=0; break;
212 								}
213 								m[ch].command = command;
214 								m[ch].param = param;
215 							}
216 						} else
217 						{
218 							m[ch].command = cmd;
219 							m[ch].param = b2;
220 							ConvertModCommand(&m[ch]);
221 						}
222 					}
223 				}
224 				if (b1 & 0x80)
225 				{
226 					b1 = p[i++];
227 					if (i <= len) goto anothercommand;
228 				}
229 			}
230 			if (b0 & 0x80)
231 			{
232 				row++;
233 				m += m_nChannels;
234 			}
235 		}
236 		dwMemPos += len;
237 	}
238 	// Read Samples
239 	for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength)
240 	{
241 		if (dwMemPos >= dwMemLength - 9) return TRUE;
242 		UINT flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8;
243 		dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
244 	}
245 	return TRUE;
246 }
247 
248 
249 /////////////////////////////////////////////////////////////////////
250 // AMS 2.2 loader
251 
252 #pragma pack(1)
253 
254 typedef struct AMS2FILEHEADER
255 {
256 	DWORD dwHdr1;		// AMShdr
257 	WORD wHdr2;
258 	BYTE b1A;			// 0x1A
259 	BYTE titlelen;		// 30-bytes max
260 	CHAR szTitle[30];	// [titlelen]
261 } AMS2FILEHEADER;
262 
263 typedef struct AMS2SONGHEADER
264 {
265 	WORD version;
266 	BYTE instruments;
267 	WORD patterns;
268 	WORD orders;
269 	WORD bpm;
270 	BYTE speed;
271 	BYTE channels;
272 	BYTE commands;
273 	BYTE rows;
274 	WORD flags;
275 } AMS2SONGHEADER;
276 
277 typedef struct AMS2INSTRUMENT
278 {
279 	BYTE samples;
280 	BYTE notemap[NOTE_MAX];
281 } AMS2INSTRUMENT;
282 
283 typedef struct AMS2ENVELOPE
284 {
285 	BYTE speed;
286 	BYTE sustain;
287 	BYTE loopbegin;
288 	BYTE loopend;
289 	BYTE points;
290 	BYTE info[3];
291 } AMS2ENVELOPE;
292 
293 typedef struct AMS2SAMPLE
294 {
295 	DWORD length;
296 	DWORD loopstart;
297 	DWORD loopend;
298 	WORD frequency;
299 	BYTE finetune;
300 	WORD c4speed;
301 	CHAR transpose;
302 	BYTE volume;
303 	BYTE flags;
304 } AMS2SAMPLE;
305 
306 
307 #pragma pack()
308 
309 
ReadAMS2(LPCBYTE lpStream,DWORD dwMemLength)310 BOOL CSoundFile::ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength)
311 //------------------------------------------------------------
312 {
313 	const AMS2FILEHEADER *pfh = (AMS2FILEHEADER *)lpStream;
314 	AMS2SONGHEADER *psh;
315 	DWORD dwMemPos;
316 	BYTE smpmap[16];
317 	BYTE packedsamples[MAX_SAMPLES];
318 
319 	if ((pfh->dwHdr1 != 0x68534D41) || (pfh->wHdr2 != 0x7264)
320 	 || (pfh->b1A != 0x1A) || (pfh->titlelen > 30)) return FALSE;
321 	dwMemPos = pfh->titlelen + 8;
322 	psh = (AMS2SONGHEADER *)(lpStream + dwMemPos);
323 	if (((psh->version & 0xFF00) != 0x0200) || (!psh->instruments)
324 	 || (psh->instruments >= MAX_INSTRUMENTS) || (!psh->patterns) || (!psh->orders)) return FALSE;
325 	dwMemPos += sizeof(AMS2SONGHEADER);
326 	if (pfh->titlelen)
327 	{
328 		memcpy(m_szNames, pfh->szTitle, pfh->titlelen);
329 		m_szNames[0][pfh->titlelen] = 0;
330 	}
331 	m_nType = MOD_TYPE_AMS;
332 	m_nChannels = 32;
333 	m_nDefaultTempo = psh->bpm >> 8;
334 	m_nDefaultSpeed = psh->speed;
335 	m_nInstruments = psh->instruments;
336 	m_nSamples = 0;
337 	if (psh->flags & 0x40) m_dwSongFlags |= SONG_LINEARSLIDES;
338 	for (UINT nIns=1; nIns<=m_nInstruments; nIns++)
339 	{
340 		UINT insnamelen = lpStream[dwMemPos];
341 		CHAR *pinsname = (CHAR *)(lpStream+dwMemPos+1);
342 		dwMemPos += insnamelen + 1;
343 		AMS2INSTRUMENT *pins = (AMS2INSTRUMENT *)(lpStream + dwMemPos);
344 		dwMemPos += sizeof(AMS2INSTRUMENT);
345 		if (dwMemPos + 1024 >= dwMemLength) return TRUE;
346 		AMS2ENVELOPE *volenv, *panenv, *pitchenv;
347 		volenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
348 		dwMemPos += 5 + volenv->points*3;
349 		panenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
350 		dwMemPos += 5 + panenv->points*3;
351 		pitchenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
352 		dwMemPos += 5 + pitchenv->points*3;
353 		INSTRUMENTHEADER *penv = new INSTRUMENTHEADER;
354 		if (!penv) return TRUE;
355 		memset(smpmap, 0, sizeof(smpmap));
356 		memset(penv, 0, sizeof(INSTRUMENTHEADER));
357 		for (UINT ismpmap=0; ismpmap<pins->samples; ismpmap++)
358 		{
359 			if ((ismpmap >= 16) || (m_nSamples+1 >= MAX_SAMPLES)) break;
360 			m_nSamples++;
361 			smpmap[ismpmap] = m_nSamples;
362 		}
363 		penv->nGlobalVol = 64;
364 		penv->nPan = 128;
365 		penv->nPPC = 60;
366 		Headers[nIns] = penv;
367 		if (insnamelen)
368 		{
369 			if (insnamelen > 31) insnamelen = 31;
370 			memcpy(penv->name, pinsname, insnamelen);
371 			penv->name[insnamelen] = 0;
372 		}
373 		for (UINT inotemap=0; inotemap<NOTE_MAX; inotemap++)
374 		{
375 			penv->NoteMap[inotemap] = inotemap+1;
376 			penv->Keyboard[inotemap] = smpmap[pins->notemap[inotemap] & 0x0F];
377 		}
378 		// Volume Envelope
379 		{
380 			UINT pos = 0;
381 			penv->nVolEnv = (volenv->points > 16) ? 16 : volenv->points;
382 			penv->nVolSustainBegin = penv->nVolSustainEnd = volenv->sustain;
383 			penv->nVolLoopStart = volenv->loopbegin;
384 			penv->nVolLoopEnd = volenv->loopend;
385 			for (UINT i=0; i<penv->nVolEnv; i++)
386 			{
387 				penv->VolEnv[i] = (BYTE)((volenv->info[i*3+2] & 0x7F) >> 1);
388 				pos += volenv->info[i*3] + ((volenv->info[i*3+1] & 1) << 8);
389 				penv->VolPoints[i] = (WORD)pos;
390 			}
391 		}
392 		penv->nFadeOut = (((lpStream[dwMemPos+2] & 0x0F) << 8) | (lpStream[dwMemPos+1])) << 3;
393 		UINT envflags = lpStream[dwMemPos+3];
394 		if (envflags & 0x01) penv->dwFlags |= ENV_VOLLOOP;
395 		if (envflags & 0x02) penv->dwFlags |= ENV_VOLSUSTAIN;
396 		if (envflags & 0x04) penv->dwFlags |= ENV_VOLUME;
397 		dwMemPos += 5;
398 		// Read Samples
399 		for (UINT ismp=0; ismp<pins->samples; ismp++)
400 		{
401 			MODINSTRUMENT *psmp = ((ismp < 16) && (smpmap[ismp])) ? &Ins[smpmap[ismp]] : NULL;
402 			UINT smpnamelen = lpStream[dwMemPos];
403 			if ((psmp) && (smpnamelen) && (smpnamelen <= 22))
404 			{
405 				memcpy(m_szNames[smpmap[ismp]], lpStream+dwMemPos+1, smpnamelen);
406 			}
407 			dwMemPos += smpnamelen + 1;
408 			if (psmp)
409 			{
410 				AMS2SAMPLE *pams = (AMS2SAMPLE *)(lpStream+dwMemPos);
411 				psmp->nGlobalVol = 64;
412 				psmp->nPan = 128;
413 				psmp->nLength = pams->length;
414 				psmp->nLoopStart = pams->loopstart;
415 				psmp->nLoopEnd = pams->loopend;
416 				psmp->nC4Speed = pams->c4speed;
417 				psmp->RelativeTone = pams->transpose;
418 				psmp->nVolume = pams->volume / 2;
419 				packedsamples[smpmap[ismp]] = pams->flags;
420 				if (pams->flags & 0x04) psmp->uFlags |= CHN_16BIT;
421 				if (pams->flags & 0x08) psmp->uFlags |= CHN_LOOP;
422 				if (pams->flags & 0x10) psmp->uFlags |= CHN_PINGPONGLOOP;
423 			}
424 			dwMemPos += sizeof(AMS2SAMPLE);
425 		}
426 	}
427 	if (dwMemPos + 256 >= dwMemLength) return TRUE;
428 	// Comments
429 	{
430 		UINT composernamelen = lpStream[dwMemPos];
431 		if (composernamelen)
432 		{
433 			m_lpszSongComments = new char[composernamelen+1]; // changed from CHAR
434 			if (m_lpszSongComments)
435 			{
436 				memcpy(m_lpszSongComments, lpStream+dwMemPos+1, composernamelen);
437 				m_lpszSongComments[composernamelen] = 0;
438 			}
439 		}
440 		dwMemPos += composernamelen + 1;
441 		// channel names
442 		for (UINT i=0; i<32; i++)
443 		{
444 			UINT chnnamlen = lpStream[dwMemPos];
445 			if ((chnnamlen) && (chnnamlen < MAX_CHANNELNAME))
446 			{
447 				memcpy(ChnSettings[i].szName, lpStream+dwMemPos+1, chnnamlen);
448 			}
449 			dwMemPos += chnnamlen + 1;
450 			if (dwMemPos + chnnamlen + 256 >= dwMemLength) return TRUE;
451 		}
452 		// packed comments (ignored)
453 		UINT songtextlen = *((LPDWORD)(lpStream+dwMemPos));
454 		dwMemPos += songtextlen;
455 		if (dwMemPos + 256 >= dwMemLength) return TRUE;
456 	}
457 	// Order List
458 	{
459 		for (UINT i=0; i<MAX_ORDERS; i++)
460 		{
461 			Order[i] = 0xFF;
462 			if (dwMemPos + 2 >= dwMemLength) return TRUE;
463 			if (i < psh->orders)
464 			{
465 				Order[i] = lpStream[dwMemPos];
466 				dwMemPos += 2;
467 			}
468 		}
469 	}
470 	// Pattern Data
471 	for (UINT ipat=0; ipat<psh->patterns; ipat++)
472 	{
473 		if (dwMemPos+8 >= dwMemLength) return TRUE;
474 		UINT packedlen = *((LPDWORD)(lpStream+dwMemPos));
475 		UINT numrows = 1 + (UINT)(lpStream[dwMemPos+4]);
476 		//UINT patchn = 1 + (UINT)(lpStream[dwMemPos+5] & 0x1F);
477 		//UINT patcmds = 1 + (UINT)(lpStream[dwMemPos+5] >> 5);
478 		UINT patnamlen = lpStream[dwMemPos+6];
479 		dwMemPos += 4;
480 		if ((ipat < MAX_PATTERNS) && (packedlen < dwMemLength-dwMemPos) && (numrows >= 8))
481 		{
482 			if ((patnamlen) && (patnamlen < MAX_PATTERNNAME))
483 			{
484 				char s[MAX_PATTERNNAME]; // changed from CHAR
485 				memcpy(s, lpStream+dwMemPos+3, patnamlen);
486 				s[patnamlen] = 0;
487 				SetPatternName(ipat, s);
488 			}
489 			PatternSize[ipat] = numrows;
490 			Patterns[ipat] = AllocatePattern(numrows, m_nChannels);
491 			if (!Patterns[ipat]) return TRUE;
492 			// Unpack Pattern Data
493 			LPCBYTE psrc = lpStream + dwMemPos;
494 			UINT pos = 3 + patnamlen;
495 			UINT row = 0;
496 			while ((pos < packedlen) && (row < numrows))
497 			{
498 				MODCOMMAND *m = Patterns[ipat] + row * m_nChannels;
499 				UINT byte1 = psrc[pos++];
500 				UINT ch = byte1 & 0x1F;
501 				// Read Note + Instr
502 				if (!(byte1 & 0x40))
503 				{
504 					UINT byte2 = psrc[pos++];
505 					UINT note = byte2 & 0x7F;
506 					if (note) m[ch].note = (note > 1) ? (note-1) : 0xFF;
507 					m[ch].instr = psrc[pos++];
508 					// Read Effect
509 					while (byte2 & 0x80)
510 					{
511 						byte2 = psrc[pos++];
512 						if (byte2 & 0x40)
513 						{
514 							m[ch].volcmd = VOLCMD_VOLUME;
515 							m[ch].vol = byte2 & 0x3F;
516 						} else
517 						{
518 							UINT command = byte2 & 0x3F;
519 							UINT param = psrc[pos++];
520 							if (command == 0x0C)
521 							{
522 								m[ch].volcmd = VOLCMD_VOLUME;
523 								m[ch].vol = param / 2;
524 							} else
525 							if (command < 0x10)
526 							{
527 								m[ch].command = command;
528 								m[ch].param = param;
529 								ConvertModCommand(&m[ch]);
530 							} else
531 							{
532 								// TODO: AMS effects
533 							}
534 						}
535 					}
536 				}
537 				if (byte1 & 0x80) row++;
538 			}
539 		}
540 		dwMemPos += packedlen;
541 	}
542 	// Read Samples
543 	for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength)
544 	{
545 		if (dwMemPos >= dwMemLength - 9) return TRUE;
546 		UINT flags;
547 		if (packedsamples[iSmp] & 0x03)
548 		{
549 			flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8;
550 		} else
551 		{
552 			flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
553 		}
554 		dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
555 	}
556 	return TRUE;
557 }
558 
559 
560 /////////////////////////////////////////////////////////////////////
561 // AMS Sample unpacking
562 
AMSUnpack(const char * psrc,UINT inputlen,char * pdest,UINT dmax,char packcharacter)563 void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char packcharacter)
564 {
565 	UINT tmplen = dmax;
566 	signed char *amstmp = new signed char[tmplen];
567 
568 	if (!amstmp) return;
569 	// Unpack Loop
570 	{
571 		signed char *p = amstmp;
572 		UINT i=0, j=0;
573 		while ((i < inputlen) && (j < tmplen))
574 		{
575 			signed char ch = psrc[i++];
576 			if (ch == packcharacter)
577 			{
578 				BYTE ch2 = psrc[i++];
579 				if (ch2)
580 				{
581 					ch = psrc[i++];
582 					while (ch2--)
583 					{
584 						p[j++] = ch;
585 						if (j >= tmplen) break;
586 					}
587 				} else p[j++] = packcharacter;
588 			} else p[j++] = ch;
589 		}
590 	}
591 	// Bit Unpack Loop
592 	{
593 		signed char *p = amstmp;
594 		UINT bitcount = 0x80, dh;
595 		UINT k=0;
596 		for (UINT i=0; i<dmax; i++)
597 		{
598 			BYTE al = *p++;
599 			dh = 0;
600 			for (UINT count=0; count<8; count++)
601 			{
602 				UINT bl = al & bitcount;
603 				bl = ((bl|(bl<<8)) >> ((dh+8-count) & 7)) & 0xFF;
604 				bitcount = ((bitcount|(bitcount<<8)) >> 1) & 0xFF;
605 				pdest[k++] |= bl;
606 				if (k >= dmax)
607 				{
608 					k = 0;
609 					dh++;
610 				}
611 			}
612 			bitcount = ((bitcount|(bitcount<<8)) >> dh) & 0xFF;
613 		}
614 	}
615 	// Delta Unpack
616 	{
617 		signed char old = 0;
618 		for (UINT i=0; i<dmax; i++)
619 		{
620 			int pos = ((LPBYTE)pdest)[i];
621 			if ((pos != 128) && (pos & 0x80)) pos = -(pos & 0x7F);
622 			old -= (signed char)pos;
623 			pdest[i] = old;
624 		}
625 	}
626 	delete[] amstmp;
627 }
628 
629