summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer/modplug/load_mod.cpp
Unidiff
Diffstat (limited to 'core/multimedia/opieplayer/modplug/load_mod.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/multimedia/opieplayer/modplug/load_mod.cpp501
1 files changed, 501 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/modplug/load_mod.cpp b/core/multimedia/opieplayer/modplug/load_mod.cpp
new file mode 100644
index 0000000..3ca8e5b
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_mod.cpp
@@ -0,0 +1,501 @@
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 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
9*/
10
11#include "stdafx.h"
12#include "sndfile.h"
13
14//#pragma warning(disable:4244)
15
16extern WORD ProTrackerPeriodTable[6*12];
17
18//////////////////////////////////////////////////////////
19// ProTracker / NoiseTracker MOD/NST file support
20
21void CSoundFile::ConvertModCommand(MODCOMMAND *m) const
22//-----------------------------------------------------
23{
24 UINT command = m->command, param = m->param;
25
26 switch(command)
27 {
28 case 0x00:if (param) command = CMD_ARPEGGIO; break;
29 case 0x01:command = CMD_PORTAMENTOUP; break;
30 case 0x02:command = CMD_PORTAMENTODOWN; break;
31 case 0x03:command = CMD_TONEPORTAMENTO; break;
32 case 0x04:command = CMD_VIBRATO; break;
33 case 0x05:command = CMD_TONEPORTAVOL; if (param & 0xF0) param &= 0xF0; break;
34 case 0x06:command = CMD_VIBRATOVOL; if (param & 0xF0) param &= 0xF0; break;
35 case 0x07:command = CMD_TREMOLO; break;
36 case 0x08:command = CMD_PANNING8; break;
37 case 0x09:command = CMD_OFFSET; break;
38 case 0x0A:command = CMD_VOLUMESLIDE; if (param & 0xF0) param &= 0xF0; break;
39 case 0x0B:command = CMD_POSITIONJUMP; break;
40 case 0x0C:command = CMD_VOLUME; break;
41 case 0x0D:command = CMD_PATTERNBREAK; param = ((param >> 4) * 10) + (param & 0x0F); break;
42 case 0x0E:command = CMD_MODCMDEX; break;
43 case 0x0F:command = (param <= (UINT)((m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) ? 0x1F : 0x20)) ? CMD_SPEED : CMD_TEMPO;
44 if ((param == 0xFF) && (m_nSamples == 15)) command = 0; break;
45 // Extension for XM extended effects
46 case 'G' - 55:command = CMD_GLOBALVOLUME; break;
47 case 'H' - 55:command = CMD_GLOBALVOLSLIDE; if (param & 0xF0) param &= 0xF0; break;
48 case 'K' - 55:command = CMD_KEYOFF; break;
49 case 'L' - 55:command = CMD_SETENVPOSITION; break;
50 case 'M' - 55:command = CMD_CHANNELVOLUME; break;
51 case 'N' - 55:command = CMD_CHANNELVOLSLIDE; break;
52 case 'P' - 55:command = CMD_PANNINGSLIDE; if (param & 0xF0) param &= 0xF0; break;
53 case 'R' - 55:command = CMD_RETRIG; break;
54 case 'T' - 55:command = CMD_TREMOR; break;
55 case 'X' - 55: command = CMD_XFINEPORTAUPDOWN;break;
56 case 'Y' - 55:command = CMD_PANBRELLO; break;
57 case 'Z' - 55: command = CMD_MIDI;break;
58 default:command = 0;
59 }
60 m->command = command;
61 m->param = param;
62}
63
64
65WORD CSoundFile::ModSaveCommand(const MODCOMMAND *m, BOOL bXM) const
66//------------------------------------------------------------------
67{
68 UINT command = m->command & 0x3F, param = m->param;
69
70 switch(command)
71 {
72 case 0: command = param = 0; break;
73 case CMD_ARPEGGIO: command = 0; break;
74 case CMD_PORTAMENTOUP:
75 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM))
76 {
77 if ((param & 0xF0) == 0xE0) { command=0x0E; param=((param & 0x0F) >> 2)|0x10; break; }
78 else if ((param & 0xF0) == 0xF0) { command=0x0E; param &= 0x0F; param|=0x10; break; }
79 }
80 command = 0x01;
81 break;
82 case CMD_PORTAMENTODOWN:
83 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM))
84 {
85 if ((param & 0xF0) == 0xE0) { command=0x0E; param=((param & 0x0F) >> 2)|0x20; break; }
86 else if ((param & 0xF0) == 0xF0) { command=0x0E; param &= 0x0F; param|=0x20; break; }
87 }
88 command = 0x02;
89 break;
90 case CMD_TONEPORTAMENTO:command = 0x03; break;
91 case CMD_VIBRATO: command = 0x04; break;
92 case CMD_TONEPORTAVOL: command = 0x05; break;
93 case CMD_VIBRATOVOL: command = 0x06; break;
94 case CMD_TREMOLO: command = 0x07; break;
95 case CMD_PANNING8:
96 command = 0x08;
97 if (bXM)
98 {
99 if ((m_nType != MOD_TYPE_IT) && (m_nType != MOD_TYPE_XM) && (param <= 0x80))
100 {
101 param <<= 1;
102 if (param > 255) param = 255;
103 }
104 } else
105 {
106 if ((m_nType == MOD_TYPE_IT) || (m_nType == MOD_TYPE_XM)) param >>= 1;
107 }
108 break;
109 case CMD_OFFSET: command = 0x09; break;
110 case CMD_VOLUMESLIDE: command = 0x0A; break;
111 case CMD_POSITIONJUMP: command = 0x0B; break;
112 case CMD_VOLUME: command = 0x0C; break;
113 case CMD_PATTERNBREAK: command = 0x0D; param = ((param / 10) << 4) | (param % 10); break;
114 case CMD_MODCMDEX: command = 0x0E; break;
115 case CMD_SPEED: command = 0x0F; if (param > 0x20) param = 0x20; break;
116 case CMD_TEMPO: if (param > 0x20) { command = 0x0F; break; }
117 case CMD_GLOBALVOLUME: command = 'G' - 55; break;
118 case CMD_GLOBALVOLSLIDE:command = 'H' - 55; break;
119 case CMD_KEYOFF: command = 'K' - 55; break;
120 case CMD_SETENVPOSITION:command = 'L' - 55; break;
121 case CMD_CHANNELVOLUME: command = 'M' - 55; break;
122 case CMD_CHANNELVOLSLIDE:command = 'N' - 55; break;
123 case CMD_PANNINGSLIDE: command = 'P' - 55; break;
124 case CMD_RETRIG: command = 'R' - 55; break;
125 case CMD_TREMOR: command = 'T' - 55; break;
126 case CMD_XFINEPORTAUPDOWN:command = 'X' - 55; break;
127 case CMD_PANBRELLO: command = 'Y' - 55; break;
128 case CMD_MIDI: command = 'Z' - 55; break;
129 case CMD_S3MCMDEX:
130 switch(param & 0xF0)
131 {
132 case 0x10:command = 0x0E; param = (param & 0x0F) | 0x30; break;
133 case 0x20:command = 0x0E; param = (param & 0x0F) | 0x50; break;
134 case 0x30:command = 0x0E; param = (param & 0x0F) | 0x40; break;
135 case 0x40:command = 0x0E; param = (param & 0x0F) | 0x70; break;
136 case 0x90:command = 'X' - 55; break;
137 case 0xB0:command = 0x0E; param = (param & 0x0F) | 0x60; break;
138 case 0xA0:
139 case 0x50:
140 case 0x70:
141 case 0x60:command = param = 0; break;
142 default:command = 0x0E; break;
143 }
144 break;
145 default: command = param = 0;
146 }
147 return (WORD)((command << 8) | (param));
148}
149
150
151#pragma pack(1)
152
153typedef struct _MODSAMPLE
154{
155 CHAR name[22];
156 WORD length;
157 BYTE finetune;
158 BYTE volume;
159 WORD loopstart;
160 WORD looplen;
161} Q_PACKED MODSAMPLE, *PMODSAMPLE;
162
163typedef struct _MODMAGIC
164{
165 BYTE nOrders;
166 BYTE nRestartPos;
167 BYTE Orders[128];
168 char Magic[4]; // changed from CHAR
169} Q_PACKED MODMAGIC, *PMODMAGIC;
170
171#pragma pack()
172
173BOOL IsMagic(LPCSTR s1, LPCSTR s2)
174{
175 return ((*(DWORD *)s1) == (*(DWORD *)s2)) ? TRUE : FALSE;
176}
177
178
179BOOL CSoundFile::ReadMod(const BYTE *lpStream, DWORD dwMemLength)
180//---------------------------------------------------------------
181{
182 char s[1024]; // changed from CHAR
183 DWORD dwMemPos, dwTotalSampleLen;
184 PMODMAGIC pMagic;
185 UINT nErr;
186
187 if ((!lpStream) || (dwMemLength < 0x600)) return FALSE;
188 dwMemPos = 20;
189 m_nSamples = 31;
190 m_nChannels = 4;
191 pMagic = (PMODMAGIC)(lpStream+dwMemPos+sizeof(MODSAMPLE)*31);
192 // Check Mod Magic
193 memcpy(s, pMagic->Magic, 4);
194 if ((IsMagic(s, "M.K.")) || (IsMagic(s, "M!K!"))
195 || (IsMagic(s, "M&K!")) || (IsMagic(s, "N.T."))) m_nChannels = 4; else
196 if ((IsMagic(s, "CD81")) || (IsMagic(s, "OKTA"))) m_nChannels = 8; else
197 if ((s[0]=='F') && (s[1]=='L') && (s[2]=='T') && (s[3]>='4') && (s[3]<='9')) m_nChannels = s[3] - '0'; else
198 if ((s[0]>='4') && (s[0]<='9') && (s[1]=='C') && (s[2]=='H') && (s[3]=='N')) m_nChannels = s[0] - '0'; else
199 if ((s[0]=='1') && (s[1]>='0') && (s[1]<='9') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 10; else
200 if ((s[0]=='2') && (s[1]>='0') && (s[1]<='9') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 20; else
201 if ((s[0]=='3') && (s[1]>='0') && (s[1]<='2') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 30; else
202 if ((s[0]=='T') && (s[1]=='D') && (s[2]=='Z') && (s[3]>='4') && (s[3]<='9')) m_nChannels = s[3] - '0'; else
203 if (IsMagic(s,"16CN")) m_nChannels = 16; else
204 if (IsMagic(s,"32CN")) m_nChannels = 32; else m_nSamples = 15;
205 // Load Samples
206 nErr = 0;
207 dwTotalSampleLen = 0;
208 for(UINT i=1; i<=m_nSamples; i++)
209 {
210 PMODSAMPLE pms = (PMODSAMPLE)(lpStream+dwMemPos);
211 MODINSTRUMENT *psmp = &Ins[i];
212 UINT loopstart, looplen;
213
214 memcpy(m_szNames[i], pms->name, 22);
215 m_szNames[i][22] = 0;
216 psmp->uFlags = 0;
217 psmp->nLength = bswapBE16(pms->length)*2;
218 dwTotalSampleLen += psmp->nLength;
219 psmp->nFineTune = MOD2XMFineTune(pms->finetune & 0x0F);
220 psmp->nVolume = 4*pms->volume;
221 if (psmp->nVolume > 256) { psmp->nVolume = 256; nErr++; }
222 psmp->nGlobalVol = 64;
223 psmp->nPan = 128;
224 loopstart = bswapBE16(pms->loopstart)*2;
225 looplen = bswapBE16(pms->looplen)*2;
226 // Fix loops
227 if ((looplen > 2) && (loopstart+looplen > psmp->nLength)
228 && (loopstart/2+looplen <= psmp->nLength))
229 {
230 loopstart /= 2;
231 }
232 psmp->nLoopStart = loopstart;
233 psmp->nLoopEnd = loopstart + looplen;
234 if (psmp->nLength < 4) psmp->nLength = 0;
235 if (psmp->nLength)
236 {
237 UINT derr = 0;
238 if (psmp->nLoopStart >= psmp->nLength) { psmp->nLoopStart = psmp->nLength-1; derr|=1; }
239 if (psmp->nLoopEnd > psmp->nLength) { psmp->nLoopEnd = psmp->nLength; derr |= 1; }
240 if (psmp->nLoopStart > psmp->nLoopEnd) derr |= 1;
241 if ((psmp->nLoopStart > psmp->nLoopEnd) || (psmp->nLoopEnd <= 8)
242 || (psmp->nLoopEnd - psmp->nLoopStart <= 4))
243 {
244 psmp->nLoopStart = 0;
245 psmp->nLoopEnd = 0;
246 }
247 if (psmp->nLoopEnd > psmp->nLoopStart)
248 {
249 psmp->uFlags |= CHN_LOOP;
250 }
251 }
252 dwMemPos += sizeof(MODSAMPLE);
253 }
254 if ((m_nSamples == 15) && (dwTotalSampleLen > dwMemLength * 4)) return FALSE;
255 pMagic = (PMODMAGIC)(lpStream+dwMemPos);
256 dwMemPos += sizeof(MODMAGIC);
257 if (m_nSamples == 15) dwMemPos -= 4;
258 memset(Order, 0,sizeof(Order));
259 memcpy(Order, pMagic->Orders, 128);
260
261 UINT nbp, nbpbuggy, nbpbuggy2, norders;
262
263 norders = pMagic->nOrders;
264 if ((!norders) || (norders > 0x80))
265 {
266 norders = 0x80;
267 while ((norders > 1) && (!Order[norders-1])) norders--;
268 }
269 nbpbuggy = 0;
270 nbpbuggy2 = 0;
271 nbp = 0;
272 for (UINT iord=0; iord<128; iord++)
273 {
274 UINT i = Order[iord];
275 if ((i < 0x80) && (nbp <= i))
276 {
277 nbp = i+1;
278 if (iord<norders) nbpbuggy = nbp;
279 }
280 if (i >= nbpbuggy2) nbpbuggy2 = i+1;
281 }
282 for (UINT iend=norders; iend<MAX_ORDERS; iend++) Order[iend] = 0xFF;
283 norders--;
284 m_nRestartPos = pMagic->nRestartPos;
285 if (m_nRestartPos >= 0x78) m_nRestartPos = 0;
286 if (m_nRestartPos + 1 >= (UINT)norders) m_nRestartPos = 0;
287 if (!nbp) return FALSE;
288 DWORD dwWowTest = dwTotalSampleLen+dwMemPos;
289 if ((IsMagic(pMagic->Magic, "M.K.")) && (dwWowTest + nbp*8*256 == dwMemLength)) m_nChannels = 8;
290 if ((nbp != nbpbuggy) && (dwWowTest + nbp*m_nChannels*256 != dwMemLength))
291 {
292 if (dwWowTest + nbpbuggy*m_nChannels*256 == dwMemLength) nbp = nbpbuggy;
293 else nErr += 8;
294 } else
295 if ((nbpbuggy2 > nbp) && (dwWowTest + nbpbuggy2*m_nChannels*256 == dwMemLength))
296 {
297 nbp = nbpbuggy2;
298 }
299 if ((dwWowTest < 0x600) || (dwWowTest > dwMemLength)) nErr += 8;
300 if ((m_nSamples == 15) && (nErr >= 16)) return FALSE;
301 // Default settings
302 m_nType = MOD_TYPE_MOD;
303 m_nDefaultSpeed = 6;
304 m_nDefaultTempo = 125;
305 m_nMinPeriod = 14 << 2;
306 m_nMaxPeriod = 3424 << 2;
307 memcpy(m_szNames, lpStream, 20);
308 // Setting channels pan
309 for (UINT ich=0; ich<m_nChannels; ich++)
310 {
311 ChnSettings[ich].nVolume = 64;
312 if (gdwSoundSetup & SNDMIX_MAXDEFAULTPAN)
313 ChnSettings[ich].nPan = (((ich&3)==1) || ((ich&3)==2)) ? 256 : 0;
314 else
315 ChnSettings[ich].nPan = (((ich&3)==1) || ((ich&3)==2)) ? 0xC0 : 0x40;
316 }
317 // Reading channels
318 for (UINT ipat=0; ipat<nbp; ipat++)
319 {
320 if (ipat < MAX_PATTERNS)
321 {
322 if ((Patterns[ipat] = AllocatePattern(64, m_nChannels)) == NULL) break;
323 PatternSize[ipat] = 64;
324 if (dwMemPos + m_nChannels*256 >= dwMemLength) break;
325 MODCOMMAND *m = Patterns[ipat];
326 LPCBYTE p = lpStream + dwMemPos;
327 for (UINT j=m_nChannels*64; j; m++,p+=4,j--)
328 {
329 BYTE A0=p[0], A1=p[1], A2=p[2], A3=p[3];
330 UINT n = ((((UINT)A0 & 0x0F) << 8) | (A1));
331 if ((n) && (n != 0xFFF)) m->note = GetNoteFromPeriod(n << 2);
332 m->instr = ((UINT)A2 >> 4) | (A0 & 0x10);
333 m->command = A2 & 0x0F;
334 m->param = A3;
335 if ((m->command) || (m->param)) ConvertModCommand(m);
336 }
337 }
338 dwMemPos += m_nChannels*256;
339 }
340 // Reading instruments
341 DWORD dwErrCheck = 0;
342 for (UINT ismp=1; ismp<=m_nSamples; ismp++) if (Ins[ismp].nLength)
343 {
344 LPSTR p = (LPSTR)(lpStream+dwMemPos);
345 UINT flags = 0;
346 if (dwMemPos + 5 >= dwMemLength) break;
347 if (!strnicmp(p, "ADPCM", 5))
348 {
349 flags = 3;
350 p += 5;
351 dwMemPos += 5;
352 }
353 DWORD dwSize = ReadSample(&Ins[ismp], flags, p, dwMemLength - dwMemPos);
354 if (dwSize)
355 {
356 dwMemPos += dwSize;
357 dwErrCheck++;
358 }
359 }
360#ifdef MODPLUG_TRACKER
361 return TRUE;
362#else
363 return (dwErrCheck) ? TRUE : FALSE;
364#endif
365}
366
367
368#ifndef MODPLUG_NO_FILESAVE
369#pragma warning(disable:4100)
370
371BOOL CSoundFile::SaveMod(LPCSTR lpszFileName, UINT nPacking)
372//----------------------------------------------------------
373{
374 BYTE insmap[32];
375 UINT inslen[32];
376 BYTE bTab[32];
377 BYTE ord[128];
378 FILE *f;
379
380 if ((!m_nChannels) || (!lpszFileName)) return FALSE;
381 if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE;
382 memset(ord, 0, sizeof(ord));
383 memset(inslen, 0, sizeof(inslen));
384 if (m_nInstruments)
385 {
386 memset(insmap, 0, sizeof(insmap));
387 for (UINT i=1; i<32; i++) if (Headers[i])
388 {
389 for (UINT j=0; j<128; j++) if (Headers[i]->Keyboard[j])
390 {
391 insmap[i] = Headers[i]->Keyboard[j];
392 break;
393 }
394 }
395 } else
396 {
397 for (UINT i=0; i<32; i++) insmap[i] = (BYTE)i;
398 }
399 // Writing song name
400 fwrite(m_szNames, 20, 1, f);
401 // Writing instrument definition
402 for (UINT iins=1; iins<=31; iins++)
403 {
404 MODINSTRUMENT *pins = &Ins[insmap[iins]];
405 memcpy(bTab, m_szNames[iins],22);
406 inslen[iins] = pins->nLength;
407 if (inslen[iins] > 0x1fff0) inslen[iins] = 0x1fff0;
408 bTab[22] = inslen[iins] >> 9;
409 bTab[23] = inslen[iins] >> 1;
410 if (pins->RelativeTone < 0) bTab[24] = 0x08; else
411 if (pins->RelativeTone > 0) bTab[24] = 0x07; else
412 bTab[24] = (BYTE)XM2MODFineTune(pins->nFineTune);
413 bTab[25] = pins->nVolume >> 2;
414 bTab[26] = pins->nLoopStart >> 9;
415 bTab[27] = pins->nLoopStart >> 1;
416 bTab[28] = (pins->nLoopEnd - pins->nLoopStart) >> 9;
417 bTab[29] = (pins->nLoopEnd - pins->nLoopStart) >> 1;
418 fwrite(bTab, 30, 1, f);
419 }
420 // Writing number of patterns
421 UINT nbp=0, norders=128;
422 for (UINT iord=0; iord<128; iord++)
423 {
424 if (Order[iord] == 0xFF)
425 {
426 norders = iord;
427 break;
428 }
429 if ((Order[iord] < 0x80) && (nbp<=Order[iord])) nbp = Order[iord]+1;
430 }
431 bTab[0] = norders;
432 bTab[1] = m_nRestartPos;
433 fwrite(bTab, 2, 1, f);
434 // Writing pattern list
435 if (norders) memcpy(ord, Order, norders);
436 fwrite(ord, 128, 1, f);
437 // Writing signature
438 if (m_nChannels == 4)
439 lstrcpy((LPSTR)&bTab, "M.K.");
440 else
441 wsprintf((LPSTR)&bTab, "%luCHN", m_nChannels);
442 fwrite(bTab, 4, 1, f);
443 // Writing patterns
444 for (UINT ipat=0; ipat<nbp; ipat++) if (Patterns[ipat])
445 {
446 BYTE s[64*4];
447 MODCOMMAND *m = Patterns[ipat];
448 for (UINT i=0; i<64; i++) if (i < PatternSize[ipat])
449 {
450 LPBYTE p=s;
451 for (UINT c=0; c<m_nChannels; c++,p+=4,m++)
452 {
453 UINT param = ModSaveCommand(m, FALSE);
454 UINT command = param >> 8;
455 param &= 0xFF;
456 if (command > 0x0F) command = param = 0;
457 if ((m->vol >= 0x10) && (m->vol <= 0x50) && (!command) && (!param)) { command = 0x0C; param = m->vol - 0x10; }
458 UINT period = m->note;
459 if (period)
460 {
461 if (period < 37) period = 37;
462 period -= 37;
463 if (period >= 6*12) period = 6*12-1;
464 period = ProTrackerPeriodTable[period];
465 }
466 UINT instr = (m->instr > 31) ? 0 : m->instr;
467 p[0] = ((period >> 8) & 0x0F) | (instr & 0x10);
468 p[1] = period & 0xFF;
469 p[2] = ((instr & 0x0F) << 4) | (command & 0x0F);
470 p[3] = param;
471 }
472 fwrite(s, m_nChannels, 4, f);
473 } else
474 {
475 memset(s, 0, m_nChannels*4);
476 fwrite(s, m_nChannels, 4, f);
477 }
478 }
479 // Writing instruments
480 for (UINT ismpd=1; ismpd<=31; ismpd++) if (inslen[ismpd])
481 {
482 MODINSTRUMENT *pins = &Ins[insmap[ismpd]];
483 UINT flags = RS_PCM8S;
484#ifndef NO_PACKING
485 if (!(pins->uFlags & (CHN_16BIT|CHN_STEREO)))
486 {
487 if ((nPacking) && (CanPackSample(pins->pSample, inslen[ismpd], nPacking)))
488 {
489 fwrite("ADPCM", 1, 5, f);
490 flags = RS_ADPCM4;
491 }
492 }
493#endif
494 WriteSample(f, pins, flags, inslen[ismpd]);
495 }
496 fclose(f);
497 return TRUE;
498}
499
500#pragma warning(default:4100)
501#endif // MODPLUG_NO_FILESAVE