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