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 
ReadDBM(const BYTE * lpStream,DWORD dwMemLength)97 BOOL CSoundFile::ReadDBM(const BYTE *lpStream, DWORD dwMemLength)
98 //---------------------------------------------------------------
99 {
100 	const 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 != bswapLE32(DBM_FILE_MAGIC)) || (!pfh->songs) || (pfh->song_id != bswapLE32(DBM_ID_SONG))
106 	 || (pfh->name_id != bswapLE32(DBM_ID_NAME)) || (pfh->name_len != bswapLE32(DBM_NAMELEN))
107 	 || (pfh->info_id != bswapLE32(DBM_ID_INFO)) || (pfh->info_len != bswapLE32(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 == bswapLE32(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<NOTE_MAX; 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 == bswapLE32(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 == bswapLE32(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 == bswapLE32(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 
369