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