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_mdl.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_mdl.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | core/multimedia/opieplayer/modplug/load_mdl.cpp | 506 |
1 files changed, 506 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/modplug/load_mdl.cpp b/core/multimedia/opieplayer/modplug/load_mdl.cpp new file mode 100644 index 0000000..806b68b --- a/dev/null +++ b/core/multimedia/opieplayer/modplug/load_mdl.cpp | |||
@@ -0,0 +1,506 @@ | |||
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 | // DigiTracker (MDL) module loader // | ||
12 | ////////////////////////////////////////////// | ||
13 | #include "stdafx.h" | ||
14 | #include "sndfile.h" | ||
15 | |||
16 | //#pragma warning(disable:4244) | ||
17 | |||
18 | typedef struct MDLSONGHEADER | ||
19 | { | ||
20 | DWORD id;// "DMDL" = 0x4C444D44 | ||
21 | BYTE version; | ||
22 | } Q_PACKED MDLSONGHEADER; | ||
23 | |||
24 | |||
25 | typedef struct MDLINFOBLOCK | ||
26 | { | ||
27 | CHAR songname[32]; | ||
28 | CHAR composer[20]; | ||
29 | WORD norders; | ||
30 | WORD repeatpos; | ||
31 | BYTE globalvol; | ||
32 | BYTE speed; | ||
33 | BYTE tempo; | ||
34 | BYTE channelinfo[32]; | ||
35 | BYTE seq[256]; | ||
36 | } Q_PACKED MDLINFOBLOCK; | ||
37 | |||
38 | |||
39 | typedef struct MDLPATTERNDATA | ||
40 | { | ||
41 | BYTE channels; | ||
42 | BYTE lastrow;// nrows = lastrow+1 | ||
43 | CHAR name[16]; | ||
44 | WORD data[1]; | ||
45 | } Q_PACKED MDLPATTERNDATA; | ||
46 | |||
47 | |||
48 | void ConvertMDLCommand(MODCOMMAND *m, UINT eff, UINT data) | ||
49 | //-------------------------------------------------------- | ||
50 | { | ||
51 | UINT command = 0, param = data; | ||
52 | switch(eff) | ||
53 | { | ||
54 | case 0x01:command = CMD_PORTAMENTOUP; break; | ||
55 | case 0x02:command = CMD_PORTAMENTODOWN; break; | ||
56 | case 0x03:command = CMD_TONEPORTAMENTO; break; | ||
57 | case 0x04:command = CMD_VIBRATO; break; | ||
58 | case 0x05:command = CMD_ARPEGGIO; break; | ||
59 | case 0x07:command = (param < 0x20) ? CMD_SPEED : CMD_TEMPO; break; | ||
60 | case 0x08:command = CMD_PANNING8; param <<= 1; break; | ||
61 | case 0x0B:command = CMD_POSITIONJUMP; break; | ||
62 | case 0x0C:command = CMD_GLOBALVOLUME; break; | ||
63 | case 0x0D:command = CMD_PATTERNBREAK; param = (data & 0x0F) + (data>>4)*10; break; | ||
64 | case 0x0E: | ||
65 | command = CMD_S3MCMDEX; | ||
66 | switch(data & 0xF0) | ||
67 | { | ||
68 | case 0x00:command = 0; break; // What is E0x in MDL (there is a bunch) ? | ||
69 | case 0x10:if (param & 0x0F) { param |= 0xF0; command = CMD_PANNINGSLIDE; } else command = 0; break; | ||
70 | case 0x20:if (param & 0x0F) { param = (param << 4) | 0x0F; command = CMD_PANNINGSLIDE; } else command = 0; break; | ||
71 | case 0x30:param = (data & 0x0F) | 0x10; break; // glissando | ||
72 | case 0x40:param = (data & 0x0F) | 0x30; break; // vibrato waveform | ||
73 | case 0x60:param = (data & 0x0F) | 0xB0; break; | ||
74 | case 0x70:param = (data & 0x0F) | 0x40; break; // tremolo waveform | ||
75 | case 0x90:command = CMD_RETRIG; param &= 0x0F; break; | ||
76 | case 0xA0:param = (data & 0x0F) << 4; command = CMD_GLOBALVOLSLIDE; break; | ||
77 | case 0xB0:param = data & 0x0F; command = CMD_GLOBALVOLSLIDE; break; | ||
78 | case 0xF0:param = ((data >> 8) & 0x0F) | 0xA0; break; | ||
79 | } | ||
80 | break; | ||
81 | case 0x0F:command = CMD_SPEED; break; | ||
82 | case 0x10:if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) == 0xF0) param = ((param << 4) | 0x0F); else param >>= 2; } break; | ||
83 | case 0x20:if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) != 0xF0) param >>= 2; } break; | ||
84 | case 0x30:command = CMD_RETRIG; break; | ||
85 | case 0x40:command = CMD_TREMOLO; break; | ||
86 | case 0x50:command = CMD_TREMOR; break; | ||
87 | case 0xEF:if (param > 0xFF) param = 0xFF; command = CMD_OFFSET; break; | ||
88 | } | ||
89 | if (command) | ||
90 | { | ||
91 | m->command = command; | ||
92 | m->param = param; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | |||
97 | void UnpackMDLTrack(MODCOMMAND *pat, UINT nChannels, UINT nRows, UINT nTrack, const BYTE *lpTracks) | ||
98 | //------------------------------------------------------------------------------------------------- | ||
99 | { | ||
100 | MODCOMMAND cmd, *m = pat; | ||
101 | UINT len = *((WORD *)lpTracks); | ||
102 | UINT pos = 0, row = 0, i; | ||
103 | lpTracks += 2; | ||
104 | for (UINT ntrk=1; ntrk<nTrack; ntrk++) | ||
105 | { | ||
106 | lpTracks += len; | ||
107 | len = *((WORD *)lpTracks); | ||
108 | lpTracks += 2; | ||
109 | } | ||
110 | cmd.note = cmd.instr = 0; | ||
111 | cmd.volcmd = cmd.vol = 0; | ||
112 | cmd.command = cmd.param = 0; | ||
113 | while ((row < nRows) && (pos < len)) | ||
114 | { | ||
115 | UINT xx; | ||
116 | BYTE b = lpTracks[pos++]; | ||
117 | xx = b >> 2; | ||
118 | switch(b & 0x03) | ||
119 | { | ||
120 | case 0x01: | ||
121 | for (i=0; i<=xx; i++) | ||
122 | { | ||
123 | if (row) *m = *(m-nChannels); | ||
124 | m += nChannels; | ||
125 | row++; | ||
126 | if (row >= nRows) break; | ||
127 | } | ||
128 | break; | ||
129 | |||
130 | case 0x02: | ||
131 | if (xx < row) *m = pat[nChannels*xx]; | ||
132 | m += nChannels; | ||
133 | row++; | ||
134 | break; | ||
135 | |||
136 | case 0x03: | ||
137 | { | ||
138 | cmd.note = (xx & 0x01) ? lpTracks[pos++] : 0; | ||
139 | cmd.instr = (xx & 0x02) ? lpTracks[pos++] : 0; | ||
140 | cmd.volcmd = cmd.vol = 0; | ||
141 | cmd.command = cmd.param = 0; | ||
142 | if ((cmd.note < 120-12) && (cmd.note)) cmd.note += 12; | ||
143 | UINT volume = (xx & 0x04) ? lpTracks[pos++] : 0; | ||
144 | UINT commands = (xx & 0x08) ? lpTracks[pos++] : 0; | ||
145 | UINT command1 = commands & 0x0F; | ||
146 | UINT command2 = commands & 0xF0; | ||
147 | UINT param1 = (xx & 0x10) ? lpTracks[pos++] : 0; | ||
148 | UINT param2 = (xx & 0x20) ? lpTracks[pos++] : 0; | ||
149 | if ((command1 == 0x0E) && ((param1 & 0xF0) == 0xF0) && (!command2)) | ||
150 | { | ||
151 | param1 = ((param1 & 0x0F) << 8) | param2; | ||
152 | command1 = 0xEF; | ||
153 | command2 = param2 = 0; | ||
154 | } | ||
155 | if (volume) | ||
156 | { | ||
157 | cmd.volcmd = VOLCMD_VOLUME; | ||
158 | cmd.vol = (volume+1) >> 2; | ||
159 | } | ||
160 | ConvertMDLCommand(&cmd, command1, param1); | ||
161 | if ((cmd.command != CMD_SPEED) | ||
162 | && (cmd.command != CMD_TEMPO) | ||
163 | && (cmd.command != CMD_PATTERNBREAK)) | ||
164 | ConvertMDLCommand(&cmd, command2, param2); | ||
165 | *m = cmd; | ||
166 | m += nChannels; | ||
167 | row++; | ||
168 | } | ||
169 | break; | ||
170 | |||
171 | // Empty Slots | ||
172 | default: | ||
173 | row += xx+1; | ||
174 | m += (xx+1)*nChannels; | ||
175 | if (row >= nRows) break; | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | |||
181 | |||
182 | BOOL CSoundFile::ReadMDL(const BYTE *lpStream, DWORD dwMemLength) | ||
183 | //--------------------------------------------------------------- | ||
184 | { | ||
185 | DWORD dwMemPos, dwPos, blocklen, dwTrackPos; | ||
186 | const MDLSONGHEADER *pmsh = (const MDLSONGHEADER *)lpStream; | ||
187 | MDLINFOBLOCK *pmib; | ||
188 | MDLPATTERNDATA *pmpd; | ||
189 | UINT i,j, norders = 0, npatterns = 0, ntracks = 0; | ||
190 | UINT ninstruments = 0, nsamples = 0; | ||
191 | WORD block; | ||
192 | WORD patterntracks[MAX_PATTERNS*32]; | ||
193 | BYTE smpinfo[MAX_SAMPLES]; | ||
194 | BYTE insvolenv[MAX_INSTRUMENTS]; | ||
195 | BYTE inspanenv[MAX_INSTRUMENTS]; | ||
196 | LPCBYTE pvolenv, ppanenv, ppitchenv; | ||
197 | UINT nvolenv, npanenv, npitchenv; | ||
198 | |||
199 | if ((!lpStream) || (dwMemLength < 1024)) return FALSE; | ||
200 | if ((pmsh->id != 0x4C444D44) || ((pmsh->version & 0xF0) > 0x10)) return FALSE; | ||
201 | memset(patterntracks, 0, sizeof(patterntracks)); | ||
202 | memset(smpinfo, 0, sizeof(smpinfo)); | ||
203 | memset(insvolenv, 0, sizeof(insvolenv)); | ||
204 | memset(inspanenv, 0, sizeof(inspanenv)); | ||
205 | dwMemPos = 5; | ||
206 | dwTrackPos = 0; | ||
207 | pvolenv = ppanenv = ppitchenv = NULL; | ||
208 | nvolenv = npanenv = npitchenv = 0; | ||
209 | m_nSamples = m_nInstruments = 0; | ||
210 | while (dwMemPos+6 < dwMemLength) | ||
211 | { | ||
212 | block = *((WORD *)(lpStream+dwMemPos)); | ||
213 | blocklen = *((DWORD *)(lpStream+dwMemPos+2)); | ||
214 | dwMemPos += 6; | ||
215 | if (dwMemPos + blocklen > dwMemLength) | ||
216 | { | ||
217 | if (dwMemPos == 11) return FALSE; | ||
218 | break; | ||
219 | } | ||
220 | switch(block) | ||
221 | { | ||
222 | // IN: infoblock | ||
223 | case 0x4E49: | ||
224 | pmib = (MDLINFOBLOCK *)(lpStream+dwMemPos); | ||
225 | memcpy(m_szNames[0], pmib->songname, 32); | ||
226 | norders = pmib->norders; | ||
227 | if (norders > MAX_ORDERS) norders = MAX_ORDERS; | ||
228 | m_nRestartPos = pmib->repeatpos; | ||
229 | m_nDefaultGlobalVolume = pmib->globalvol; | ||
230 | m_nDefaultTempo = pmib->tempo; | ||
231 | m_nDefaultSpeed = pmib->speed; | ||
232 | m_nChannels = 4; | ||
233 | for (i=0; i<32; i++) | ||
234 | { | ||
235 | ChnSettings[i].nVolume = 64; | ||
236 | ChnSettings[i].nPan = (pmib->channelinfo[i] & 0x7F) << 1; | ||
237 | if (pmib->channelinfo[i] & 0x80) | ||
238 | ChnSettings[i].dwFlags |= CHN_MUTE; | ||
239 | else | ||
240 | m_nChannels = i+1; | ||
241 | } | ||
242 | for (j=0; j<norders; j++) Order[j] = pmib->seq[j]; | ||
243 | break; | ||
244 | // ME: song message | ||
245 | case 0x454D: | ||
246 | if (blocklen) | ||
247 | { | ||
248 | if (m_lpszSongComments) delete m_lpszSongComments; | ||
249 | m_lpszSongComments = new char[blocklen]; | ||
250 | if (m_lpszSongComments) | ||
251 | { | ||
252 | memcpy(m_lpszSongComments, lpStream+dwMemPos, blocklen); | ||
253 | m_lpszSongComments[blocklen-1] = 0; | ||
254 | } | ||
255 | } | ||
256 | break; | ||
257 | // PA: Pattern Data | ||
258 | case 0x4150: | ||
259 | npatterns = lpStream[dwMemPos]; | ||
260 | if (npatterns > MAX_PATTERNS) npatterns = MAX_PATTERNS; | ||
261 | dwPos = dwMemPos + 1; | ||
262 | for (i=0; i<npatterns; i++) | ||
263 | { | ||
264 | if (dwPos+18 >= dwMemLength) break; | ||
265 | pmpd = (MDLPATTERNDATA *)(lpStream + dwPos); | ||
266 | if (pmpd->channels > 32) break; | ||
267 | PatternSize[i] = pmpd->lastrow+1; | ||
268 | if (m_nChannels < pmpd->channels) m_nChannels = pmpd->channels; | ||
269 | dwPos += 18 + 2*pmpd->channels; | ||
270 | for (j=0; j<pmpd->channels; j++) | ||
271 | { | ||
272 | patterntracks[i*32+j] = pmpd->data[j]; | ||
273 | } | ||
274 | } | ||
275 | break; | ||
276 | // TR: Track Data | ||
277 | case 0x5254: | ||
278 | if (dwTrackPos) break; | ||
279 | ntracks = *((WORD *)(lpStream+dwMemPos)); | ||
280 | dwTrackPos = dwMemPos+2; | ||
281 | break; | ||
282 | // II: Instruments | ||
283 | case 0x4949: | ||
284 | ninstruments = lpStream[dwMemPos]; | ||
285 | dwPos = dwMemPos+1; | ||
286 | for (i=0; i<ninstruments; i++) | ||
287 | { | ||
288 | UINT nins = lpStream[dwPos]; | ||
289 | if ((nins >= MAX_INSTRUMENTS) || (!nins)) break; | ||
290 | if (m_nInstruments < nins) m_nInstruments = nins; | ||
291 | if (!Headers[nins]) | ||
292 | { | ||
293 | UINT note = 12; | ||
294 | if ((Headers[nins] = new INSTRUMENTHEADER) == NULL) break; | ||
295 | INSTRUMENTHEADER *penv = Headers[nins]; | ||
296 | memset(penv, 0, sizeof(INSTRUMENTHEADER)); | ||
297 | memcpy(penv->name, lpStream+dwPos+2, 32); | ||
298 | penv->nGlobalVol = 64; | ||
299 | penv->nPPC = 5*12; | ||
300 | for (j=0; j<lpStream[dwPos+1]; j++) | ||
301 | { | ||
302 | const BYTE *ps = lpStream+dwPos+34+14*j; | ||
303 | while ((note < (UINT)(ps[1]+12)) && (note < 120)) | ||
304 | { | ||
305 | penv->NoteMap[note] = note+1; | ||
306 | if (ps[0] < MAX_SAMPLES) | ||
307 | { | ||
308 | int ismp = ps[0]; | ||
309 | penv->Keyboard[note] = ps[0]; | ||
310 | Ins[ismp].nVolume = ps[2]; | ||
311 | Ins[ismp].nPan = ps[4] << 1; | ||
312 | Ins[ismp].nVibType = ps[11]; | ||
313 | Ins[ismp].nVibSweep = ps[10]; | ||
314 | Ins[ismp].nVibDepth = ps[9]; | ||
315 | Ins[ismp].nVibRate = ps[8]; | ||
316 | } | ||
317 | penv->nFadeOut = (ps[7] << 8) | ps[6]; | ||
318 | if (penv->nFadeOut == 0xFFFF) penv->nFadeOut = 0; | ||
319 | note++; | ||
320 | } | ||
321 | // Use volume envelope ? | ||
322 | if (ps[3] & 0x80) | ||
323 | { | ||
324 | penv->dwFlags |= ENV_VOLUME; | ||
325 | insvolenv[nins] = (ps[3] & 0x3F) + 1; | ||
326 | } | ||
327 | // Use panning envelope ? | ||
328 | if (ps[5] & 0x80) | ||
329 | { | ||
330 | penv->dwFlags |= ENV_PANNING; | ||
331 | inspanenv[nins] = (ps[5] & 0x3F) + 1; | ||
332 | } | ||
333 | } | ||
334 | } | ||
335 | dwPos += 34 + 14*lpStream[dwPos+1]; | ||
336 | } | ||
337 | for (j=1; j<=m_nInstruments; j++) if (!Headers[j]) | ||
338 | { | ||
339 | Headers[j] = new INSTRUMENTHEADER; | ||
340 | if (Headers[j]) memset(Headers[j], 0, sizeof(INSTRUMENTHEADER)); | ||
341 | } | ||
342 | break; | ||
343 | // VE: Volume Envelope | ||
344 | case 0x4556: | ||
345 | if ((nvolenv = lpStream[dwMemPos]) == 0) break; | ||
346 | if (dwMemPos + nvolenv*32 + 1 <= dwMemLength) pvolenv = lpStream + dwMemPos + 1; | ||
347 | break; | ||
348 | // PE: Panning Envelope | ||
349 | case 0x4550: | ||
350 | if ((npanenv = lpStream[dwMemPos]) == 0) break; | ||
351 | if (dwMemPos + npanenv*32 + 1 <= dwMemLength) ppanenv = lpStream + dwMemPos + 1; | ||
352 | break; | ||
353 | // FE: Pitch Envelope | ||
354 | case 0x4546: | ||
355 | if ((npitchenv = lpStream[dwMemPos]) == 0) break; | ||
356 | if (dwMemPos + npitchenv*32 + 1 <= dwMemLength) ppitchenv = lpStream + dwMemPos + 1; | ||
357 | break; | ||
358 | // IS: Sample Infoblock | ||
359 | case 0x5349: | ||
360 | nsamples = lpStream[dwMemPos]; | ||
361 | dwPos = dwMemPos+1; | ||
362 | for (i=0; i<nsamples; i++, dwPos += 59) | ||
363 | { | ||
364 | UINT nins = lpStream[dwPos]; | ||
365 | if ((nins >= MAX_SAMPLES) || (!nins)) continue; | ||
366 | if (m_nSamples < nins) m_nSamples = nins; | ||
367 | MODINSTRUMENT *pins = &Ins[nins]; | ||
368 | memcpy(m_szNames[nins], lpStream+dwPos+1, 32); | ||
369 | memcpy(pins->name, lpStream+dwPos+33, 8); | ||
370 | pins->nC4Speed = *((DWORD *)(lpStream+dwPos+41)); | ||
371 | pins->nLength = *((DWORD *)(lpStream+dwPos+45)); | ||
372 | pins->nLoopStart = *((DWORD *)(lpStream+dwPos+49)); | ||
373 | pins->nLoopEnd = pins->nLoopStart + *((DWORD *)(lpStream+dwPos+53)); | ||
374 | if (pins->nLoopEnd > pins->nLoopStart) pins->uFlags |= CHN_LOOP; | ||
375 | pins->nGlobalVol = 64; | ||
376 | if (lpStream[dwPos+58] & 0x01) | ||
377 | { | ||
378 | pins->uFlags |= CHN_16BIT; | ||
379 | pins->nLength >>= 1; | ||
380 | pins->nLoopStart >>= 1; | ||
381 | pins->nLoopEnd >>= 1; | ||
382 | } | ||
383 | if (lpStream[dwPos+58] & 0x02) pins->uFlags |= CHN_PINGPONGLOOP; | ||
384 | smpinfo[nins] = (lpStream[dwPos+58] >> 2) & 3; | ||
385 | } | ||
386 | break; | ||
387 | // SA: Sample Data | ||
388 | case 0x4153: | ||
389 | dwPos = dwMemPos; | ||
390 | for (i=1; i<=m_nSamples; i++) if ((Ins[i].nLength) && (!Ins[i].pSample) && (smpinfo[i] != 3) && (dwPos < dwMemLength)) | ||
391 | { | ||
392 | MODINSTRUMENT *pins = &Ins[i]; | ||
393 | UINT flags = (pins->uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S; | ||
394 | if (!smpinfo[i]) | ||
395 | { | ||
396 | dwPos += ReadSample(pins, flags, (LPSTR)(lpStream+dwPos), dwMemLength - dwPos); | ||
397 | } else | ||
398 | { | ||
399 | DWORD dwLen = *((DWORD *)(lpStream+dwPos)); | ||
400 | dwPos += 4; | ||
401 | if ((dwPos+dwLen <= dwMemLength) && (dwLen > 4)) | ||
402 | { | ||
403 | flags = (pins->uFlags & CHN_16BIT) ? RS_MDL16 : RS_MDL8; | ||
404 | ReadSample(pins, flags, (LPSTR)(lpStream+dwPos), dwLen); | ||
405 | } | ||
406 | dwPos += dwLen; | ||
407 | } | ||
408 | } | ||
409 | break; | ||
410 | } | ||
411 | dwMemPos += blocklen; | ||
412 | } | ||
413 | // Unpack Patterns | ||
414 | if ((dwTrackPos) && (npatterns) && (m_nChannels) && (ntracks)) | ||
415 | { | ||
416 | for (UINT ipat=0; ipat<npatterns; ipat++) | ||
417 | { | ||
418 | if ((Patterns[ipat] = AllocatePattern(PatternSize[ipat], m_nChannels)) == NULL) break; | ||
419 | for (UINT chn=0; chn<m_nChannels; chn++) if ((patterntracks[ipat*32+chn]) && (patterntracks[ipat*32+chn] <= ntracks)) | ||
420 | { | ||
421 | MODCOMMAND *m = Patterns[ipat] + chn; | ||
422 | UnpackMDLTrack(m, m_nChannels, PatternSize[ipat], patterntracks[ipat*32+chn], lpStream+dwTrackPos); | ||
423 | } | ||
424 | } | ||
425 | } | ||
426 | // Set up envelopes | ||
427 | for (UINT iIns=1; iIns<=m_nInstruments; iIns++) if (Headers[iIns]) | ||
428 | { | ||
429 | INSTRUMENTHEADER *penv = Headers[iIns]; | ||
430 | // Setup volume envelope | ||
431 | if ((nvolenv) && (pvolenv) && (insvolenv[iIns])) | ||
432 | { | ||
433 | LPCBYTE pve = pvolenv; | ||
434 | for (UINT nve=0; nve<nvolenv; nve++, pve+=33) if (pve[0]+1 == insvolenv[iIns]) | ||
435 | { | ||
436 | WORD vtick = 1; | ||
437 | penv->nVolEnv = 15; | ||
438 | for (UINT iv=0; iv<15; iv++) | ||
439 | { | ||
440 | if (iv) vtick += pve[iv*2+1]; | ||
441 | penv->VolPoints[iv] = vtick; | ||
442 | penv->VolEnv[iv] = pve[iv*2+2]; | ||
443 | if (!pve[iv*2+1]) | ||
444 | { | ||
445 | penv->nVolEnv = iv+1; | ||
446 | break; | ||
447 | } | ||
448 | } | ||
449 | penv->nVolSustainBegin = penv->nVolSustainEnd = pve[31] & 0x0F; | ||
450 | if (pve[31] & 0x10) penv->dwFlags |= ENV_VOLSUSTAIN; | ||
451 | if (pve[31] & 0x20) penv->dwFlags |= ENV_VOLLOOP; | ||
452 | penv->nVolLoopStart = pve[32] & 0x0F; | ||
453 | penv->nVolLoopEnd = pve[32] >> 4; | ||
454 | } | ||
455 | } | ||
456 | // Setup panning envelope | ||
457 | if ((npanenv) && (ppanenv) && (inspanenv[iIns])) | ||
458 | { | ||
459 | LPCBYTE ppe = ppanenv; | ||
460 | for (UINT npe=0; npe<npanenv; npe++, ppe+=33) if (ppe[0]+1 == inspanenv[iIns]) | ||
461 | { | ||
462 | WORD vtick = 1; | ||
463 | penv->nPanEnv = 15; | ||
464 | for (UINT iv=0; iv<15; iv++) | ||
465 | { | ||
466 | if (iv) vtick += ppe[iv*2+1]; | ||
467 | penv->PanPoints[iv] = vtick; | ||
468 | penv->PanEnv[iv] = ppe[iv*2+2]; | ||
469 | if (!ppe[iv*2+1]) | ||
470 | { | ||
471 | penv->nPanEnv = iv+1; | ||
472 | break; | ||
473 | } | ||
474 | } | ||
475 | if (ppe[31] & 0x10) penv->dwFlags |= ENV_PANSUSTAIN; | ||
476 | if (ppe[31] & 0x20) penv->dwFlags |= ENV_PANLOOP; | ||
477 | penv->nPanLoopStart = ppe[32] & 0x0F; | ||
478 | penv->nPanLoopEnd = ppe[32] >> 4; | ||
479 | } | ||
480 | } | ||
481 | } | ||
482 | m_dwSongFlags |= SONG_LINEARSLIDES; | ||
483 | m_nType = MOD_TYPE_MDL; | ||
484 | return TRUE; | ||
485 | } | ||
486 | |||
487 | |||
488 | ///////////////////////////////////////////////////////////////////////// | ||
489 | // MDL Sample Unpacking | ||
490 | |||
491 | // MDL Huffman ReadBits compression | ||
492 | WORD MDLReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n) | ||
493 | //----------------------------------------------------------------- | ||
494 | { | ||
495 | WORD v = (WORD)(bitbuf & ((1 << n) - 1) ); | ||
496 | bitbuf >>= n; | ||
497 | bitnum -= n; | ||
498 | if (bitnum <= 24) | ||
499 | { | ||
500 | bitbuf |= (((DWORD)(*ibuf++)) << bitnum); | ||
501 | bitnum += 8; | ||
502 | } | ||
503 | return v; | ||
504 | } | ||
505 | |||
506 | |||