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