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.cpp | 371 |
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 | |||
37 | typedef 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 | |||
59 | typedef 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 | |||
71 | typedef 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 | |||
83 | typedef struct DBMPATTERN | ||
84 | { | ||
85 | WORD rows; | ||
86 | DWORD packedsize; | ||
87 | BYTE patterndata[2];// [packedsize] | ||
88 | } Q_PACKED DBMPATTERN; | ||
89 | |||
90 | typedef struct DBMSAMPLE | ||
91 | { | ||
92 | DWORD flags; | ||
93 | DWORD samplesize; | ||
94 | BYTE sampledata[2]; // [samplesize] | ||
95 | } Q_PACKED DBMSAMPLE; | ||
96 | |||
97 | #pragma pack() | ||
98 | |||
99 | |||
100 | BOOL 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 | |||