summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer/modplug/load_mdl.cpp
Unidiff
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.cpp506
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
18typedef struct MDLSONGHEADER
19{
20 DWORD id;// "DMDL" = 0x4C444D44
21 BYTE version;
22} Q_PACKED MDLSONGHEADER;
23
24
25typedef 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
39typedef 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
48void 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
97void 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
182BOOL 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
492WORD 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