summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer/modplug/load_dbm.cpp
Unidiff
Diffstat (limited to 'core/multimedia/opieplayer/modplug/load_dbm.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/multimedia/opieplayer/modplug/load_dbm.cpp371
1 files changed, 371 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/modplug/load_dbm.cpp b/core/multimedia/opieplayer/modplug/load_dbm.cpp
new file mode 100644
index 0000000..258fd88
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_dbm.cpp
@@ -0,0 +1,371 @@
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///////////////////////////////////////////////////////////////
12//
13// DigiBooster Pro Module Loader (*.dbm)
14//
15// Note: this loader doesn't handle multiple songs
16//
17///////////////////////////////////////////////////////////////
18
19#include "stdafx.h"
20#include "sndfile.h"
21
22//#pragma warning(disable:4244)
23
24 #define DBM_FILE_MAGIC0x304d4244
25 #define DBM_ID_NAME 0x454d414e
26 #define DBM_NAMELEN 0x2c000000
27 #define DBM_ID_INFO 0x4f464e49
28 #define DBM_INFOLEN 0x0a000000
29 #define DBM_ID_SONG 0x474e4f53
30 #define DBM_ID_INST 0x54534e49
31 #define DBM_ID_VENV 0x564e4556
32 #define DBM_ID_PATT 0x54544150
33 #define DBM_ID_SMPL 0x4c504d53
34
35#pragma pack(1)
36
37typedef struct DBMFILEHEADER
38{
39 DWORD dbm_id; // "DBM0" = 0x304d4244
40 WORD trkver; // Tracker version: 02.15
41 WORD reserved;
42 DWORD name_id; // "NAME" = 0x454d414e
43 DWORD name_len; // name length: always 44
44 CHAR songname[44];
45 DWORD info_id; // "INFO" = 0x4f464e49
46 DWORD info_len; // 0x0a000000
47 WORD instruments;
48 WORD samples;
49 WORD songs;
50 WORD patterns;
51 WORD channels;
52 DWORD song_id; // "SONG" = 0x474e4f53
53 DWORD song_len;
54 CHAR songname2[44];
55 WORD orders;
56 // WORD orderlist[0];// orderlist[orders] in words
57} Q_PACKED DBMFILEHEADER;
58
59typedef struct DBMINSTRUMENT
60{
61 CHAR name[30];
62 WORD sampleno;
63 WORD volume;
64 DWORD finetune;
65 DWORD loopstart;
66 DWORD looplen;
67 WORD panning;
68 WORD flags;
69} Q_PACKED DBMINSTRUMENT;
70
71typedef struct DBMENVELOPE
72{
73 WORD instrument;
74 BYTE flags;
75 BYTE numpoints;
76 BYTE sustain1;
77 BYTE loopbegin;
78 BYTE loopend;
79 BYTE sustain2;
80 WORD volenv[2*32];
81} Q_PACKED DBMENVELOPE;
82
83typedef struct DBMPATTERN
84{
85 WORD rows;
86 DWORD packedsize;
87 BYTE patterndata[2];// [packedsize]
88} Q_PACKED DBMPATTERN;
89
90typedef struct DBMSAMPLE
91{
92 DWORD flags;
93 DWORD samplesize;
94 BYTE sampledata[2]; // [samplesize]
95} Q_PACKED DBMSAMPLE;
96
97#pragma pack()
98
99
100BOOL CSoundFile::ReadDBM(const BYTE *lpStream, DWORD dwMemLength)
101//---------------------------------------------------------------
102{
103 DBMFILEHEADER *pfh = (DBMFILEHEADER *)lpStream;
104 DWORD dwMemPos;
105 UINT nOrders, nSamples, nInstruments, nPatterns;
106
107 if ((!lpStream) || (dwMemLength <= sizeof(DBMFILEHEADER)) || (!pfh->channels)
108 || (pfh->dbm_id != DBM_FILE_MAGIC) || (!pfh->songs) || (pfh->song_id != DBM_ID_SONG)
109 || (pfh->name_id != DBM_ID_NAME) || (pfh->name_len != DBM_NAMELEN)
110 || (pfh->info_id != DBM_ID_INFO) || (pfh->info_len != DBM_INFOLEN)) return FALSE;
111 dwMemPos = sizeof(DBMFILEHEADER);
112 nOrders = bswapBE16(pfh->orders);
113 if (dwMemPos + 2 * nOrders + 8*3 >= dwMemLength) return FALSE;
114 nInstruments = bswapBE16(pfh->instruments);
115 nSamples = bswapBE16(pfh->samples);
116 nPatterns = bswapBE16(pfh->patterns);
117 m_nType = MOD_TYPE_DBM;
118 m_nChannels = bswapBE16(pfh->channels);
119 if (m_nChannels < 4) m_nChannels = 4;
120 if (m_nChannels > 64) m_nChannels = 64;
121 memcpy(m_szNames[0], (pfh->songname[0]) ? pfh->songname : pfh->songname2, 32);
122 m_szNames[0][31] = 0;
123 for (UINT iOrd=0; iOrd < nOrders; iOrd++)
124 {
125 Order[iOrd] = lpStream[dwMemPos+iOrd*2+1];
126 if (iOrd >= MAX_ORDERS-2) break;
127 }
128 dwMemPos += 2*nOrders;
129 while (dwMemPos + 10 < dwMemLength)
130 {
131 DWORD chunk_id = ((LPDWORD)(lpStream+dwMemPos))[0];
132 DWORD chunk_size = bswapBE32(((LPDWORD)(lpStream+dwMemPos))[1]);
133 DWORD chunk_pos;
134
135 dwMemPos += 8;
136 chunk_pos = dwMemPos;
137 if ((dwMemPos + chunk_size > dwMemLength) || (chunk_size > dwMemLength)) break;
138 dwMemPos += chunk_size;
139 // Instruments
140 if (chunk_id == DBM_ID_INST)
141 {
142 if (nInstruments >= MAX_INSTRUMENTS) nInstruments = MAX_INSTRUMENTS-1;
143 for (UINT iIns=0; iIns<nInstruments; iIns++)
144 {
145 MODINSTRUMENT *psmp;
146 INSTRUMENTHEADER *penv;
147 DBMINSTRUMENT *pih;
148 UINT nsmp;
149
150 if (chunk_pos + sizeof(DBMINSTRUMENT) > dwMemPos) break;
151 if ((penv = new INSTRUMENTHEADER) == NULL) break;
152 pih = (DBMINSTRUMENT *)(lpStream+chunk_pos);
153 nsmp = bswapBE16(pih->sampleno);
154 psmp = ((nsmp) && (nsmp < MAX_SAMPLES)) ? &Ins[nsmp] : NULL;
155 memset(penv, 0, sizeof(INSTRUMENTHEADER));
156 memcpy(penv->name, pih->name, 30);
157 if (psmp)
158 {
159 memcpy(m_szNames[nsmp], pih->name, 30);
160 m_szNames[nsmp][30] = 0;
161 }
162 Headers[iIns+1] = penv;
163 penv->nFadeOut = 1024;// ???
164 penv->nGlobalVol = 64;
165 penv->nPan = bswapBE16(pih->panning);
166 if ((penv->nPan) && (penv->nPan < 256))
167 penv->dwFlags = ENV_SETPANNING;
168 else
169 penv->nPan = 128;
170 penv->nPPC = 5*12;
171 for (UINT i=0; i<120; i++)
172 {
173 penv->Keyboard[i] = nsmp;
174 penv->NoteMap[i] = i+1;
175 }
176 // Sample Info
177 if (psmp)
178 {
179 DWORD sflags = bswapBE16(pih->flags);
180 psmp->nVolume = bswapBE16(pih->volume) * 4;
181 if ((!psmp->nVolume) || (psmp->nVolume > 256)) psmp->nVolume = 256;
182 psmp->nGlobalVol = 64;
183 psmp->nC4Speed = bswapBE32(pih->finetune);
184 int f2t = FrequencyToTranspose(psmp->nC4Speed);
185 psmp->RelativeTone = f2t >> 7;
186 psmp->nFineTune = f2t & 0x7F;
187 if ((pih->looplen) && (sflags & 3))
188 {
189 psmp->nLoopStart = bswapBE32(pih->loopstart);
190 psmp->nLoopEnd = psmp->nLoopStart + bswapBE32(pih->looplen);
191 psmp->uFlags |= CHN_LOOP;
192 psmp->uFlags &= ~CHN_PINGPONGLOOP;
193 if (sflags & 2) psmp->uFlags |= CHN_PINGPONGLOOP;
194 }
195 }
196 chunk_pos += sizeof(DBMINSTRUMENT);
197 m_nInstruments = iIns+1;
198 }
199 } else
200 // Volume Envelopes
201 if (chunk_id == DBM_ID_VENV)
202 {
203 UINT nEnvelopes = lpStream[chunk_pos+1];
204
205 chunk_pos += 2;
206 for (UINT iEnv=0; iEnv<nEnvelopes; iEnv++)
207 {
208 DBMENVELOPE *peh;
209 UINT nins;
210
211 if (chunk_pos + sizeof(DBMENVELOPE) > dwMemPos) break;
212 peh = (DBMENVELOPE *)(lpStream+chunk_pos);
213 nins = bswapBE16(peh->instrument);
214 if ((nins) && (nins < MAX_INSTRUMENTS) && (Headers[nins]) && (peh->numpoints))
215 {
216 INSTRUMENTHEADER *penv = Headers[nins];
217
218 if (peh->flags & 1) penv->dwFlags |= ENV_VOLUME;
219 if (peh->flags & 2) penv->dwFlags |= ENV_VOLSUSTAIN;
220 if (peh->flags & 4) penv->dwFlags |= ENV_VOLLOOP;
221 penv->nVolEnv = peh->numpoints + 1;
222 if (penv->nVolEnv > MAX_ENVPOINTS) penv->nVolEnv = MAX_ENVPOINTS;
223 penv->nVolLoopStart = peh->loopbegin;
224 penv->nVolLoopEnd = peh->loopend;
225 penv->nVolSustainBegin = penv->nVolSustainEnd = peh->sustain1;
226 for (UINT i=0; i<penv->nVolEnv; i++)
227 {
228 penv->VolPoints[i] = bswapBE16(peh->volenv[i*2]);
229 penv->VolEnv[i] = (BYTE)bswapBE16(peh->volenv[i*2+1]);
230 }
231 }
232 chunk_pos += sizeof(DBMENVELOPE);
233 }
234 } else
235 // Packed Pattern Data
236 if (chunk_id == DBM_ID_PATT)
237 {
238 if (nPatterns > MAX_PATTERNS) nPatterns = MAX_PATTERNS;
239 for (UINT iPat=0; iPat<nPatterns; iPat++)
240 {
241 DBMPATTERN *pph;
242 DWORD pksize;
243 UINT nRows;
244
245 if (chunk_pos + sizeof(DBMPATTERN) > dwMemPos) break;
246 pph = (DBMPATTERN *)(lpStream+chunk_pos);
247 pksize = bswapBE32(pph->packedsize);
248 if ((chunk_pos + pksize + 6 > dwMemPos) || (pksize > dwMemPos)) break;
249 nRows = bswapBE16(pph->rows);
250 if ((nRows >= 4) && (nRows <= 256))
251 {
252 MODCOMMAND *m = AllocatePattern(nRows, m_nChannels);
253 if (m)
254 {
255 LPBYTE pkdata = (LPBYTE)&pph->patterndata;
256 UINT row = 0;
257 UINT i = 0;
258
259 PatternSize[iPat] = nRows;
260 Patterns[iPat] = m;
261 while ((i+3<pksize) && (row < nRows))
262 {
263 UINT ch = pkdata[i++];
264
265 if (ch)
266 {
267 BYTE b = pkdata[i++];
268 ch--;
269 if (ch < m_nChannels)
270 {
271 if (b & 0x01)
272 {
273 UINT note = pkdata[i++];
274
275 if (note == 0x1F) note = 0xFF; else
276 if ((note) && (note < 0xFE))
277 {
278 note = ((note >> 4)*12) + (note & 0x0F) + 13;
279 }
280 m[ch].note = note;
281 }
282 if (b & 0x02) m[ch].instr = pkdata[i++];
283 if (b & 0x3C)
284 {
285 UINT cmd1 = 0xFF, param1 = 0, cmd2 = 0xFF, param2 = 0;
286 if (b & 0x04) cmd1 = (UINT)pkdata[i++];
287 if (b & 0x08) param1 = pkdata[i++];
288 if (b & 0x10) cmd2 = (UINT)pkdata[i++];
289 if (b & 0x20) param2 = pkdata[i++];
290 if (cmd1 == 0x0C)
291 {
292 m[ch].volcmd = VOLCMD_VOLUME;
293 m[ch].vol = param1;
294 cmd1 = 0xFF;
295 } else
296 if (cmd2 == 0x0C)
297 {
298 m[ch].volcmd = VOLCMD_VOLUME;
299 m[ch].vol = param2;
300 cmd2 = 0xFF;
301 }
302 if ((cmd1 > 0x13) || ((cmd1 >= 0x10) && (cmd2 < 0x10)))
303 {
304 cmd1 = cmd2;
305 param1 = param2;
306 cmd2 = 0xFF;
307 }
308 if (cmd1 <= 0x13)
309 {
310 m[ch].command = cmd1;
311 m[ch].param = param1;
312 ConvertModCommand(&m[ch]);
313 }
314 }
315 } else
316 {
317 if (b & 0x01) i++;
318 if (b & 0x02) i++;
319 if (b & 0x04) i++;
320 if (b & 0x08) i++;
321 if (b & 0x10) i++;
322 if (b & 0x20) i++;
323 }
324 } else
325 {
326 row++;
327 m += m_nChannels;
328 }
329 }
330 }
331 }
332 chunk_pos += 6 + pksize;
333 }
334 } else
335 // Reading Sample Data
336 if (chunk_id == DBM_ID_SMPL)
337 {
338 if (nSamples >= MAX_SAMPLES) nSamples = MAX_SAMPLES-1;
339 m_nSamples = nSamples;
340 for (UINT iSmp=1; iSmp<=nSamples; iSmp++)
341 {
342 MODINSTRUMENT *pins;
343 DBMSAMPLE *psh;
344 DWORD samplesize;
345 DWORD sampleflags;
346
347 if (chunk_pos + sizeof(DBMSAMPLE) >= dwMemPos) break;
348 psh = (DBMSAMPLE *)(lpStream+chunk_pos);
349 chunk_pos += 8;
350 samplesize = bswapBE32(psh->samplesize);
351 sampleflags = bswapBE32(psh->flags);
352 pins = &Ins[iSmp];
353 pins->nLength = samplesize;
354 if (sampleflags & 2)
355 {
356 pins->uFlags |= CHN_16BIT;
357 samplesize <<= 1;
358 }
359 if ((chunk_pos+samplesize > dwMemPos) || (samplesize > dwMemLength)) break;
360 if (sampleflags & 3)
361 {
362 ReadSample(pins, (pins->uFlags & CHN_16BIT) ? RS_PCM16M : RS_PCM8S,
363 (LPSTR)(psh->sampledata), samplesize);
364 }
365 chunk_pos += samplesize;
366 }
367 }
368 }
369 return TRUE;
370}
371