1 /*
2 * Copyright (c) 2009, The MilkyTracker Team.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * - Neither the name of the <ORGANIZATION> nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * LoaderDIGI.cpp
32 * MilkyPlay Module Loader: Digibooster 1.0 - 1.7
33 */
34
35 #include "Loaders.h"
36
identifyModule(const mp_ubyte * buffer)37 const char* LoaderDIGI::identifyModule(const mp_ubyte* buffer)
38 {
39 if (strcmp((const char*)buffer, "DIGI Booster module") == 0)
40 {
41 return "DIGI";
42 }
43
44 return NULL;
45 }
46
convertEvent(mp_ubyte * dst,mp_ubyte * src)47 static void convertEvent(mp_ubyte* dst, mp_ubyte* src)
48 {
49 mp_ubyte b1 = src[0];
50 mp_ubyte b2 = src[1];
51 mp_ubyte b3 = src[2];
52 mp_ubyte b4 = src[3];
53
54 mp_sint32 note,ins,eff,notenum = 0;
55 note = ((b1&0xf)<<8)+b2;
56 ins = (b1&0xf0)+(b3>>4);
57 eff = b3&0xf;
58
59 if (eff==0xE) {
60 eff=(b4>>4)+0x30;
61 b4&=0xf;
62
63 if (eff == 0x33)
64 {
65 eff = 0x4F;
66 b4 = 1;
67 }
68 if (eff == 0x34)
69 {
70 eff = 0x51; // key off at tick 0
71 b4 = 0;
72 }
73 if (eff == 0x35)
74 {
75 if (b4 == 0)
76 {
77 eff = 0x50; // AMS set channel mastervolume to zero
78 b4 = 0;
79 }
80 else if (b4 == 1)
81 {
82 eff = 0x50; // AMS set channel mastervolume to 255
83 b4 = 255;
84 }
85 }
86 if (eff == 0x38)
87 {
88 #ifdef VERBOSE
89 printf("Unsupported Digibooster effect: extended offset\n");
90 #endif
91 eff = b4 = 0;
92 }
93 if (eff == 0x39)
94 {
95 #ifdef VERBOSE
96 printf("Unsupported Digibooster effect: retrace\n");
97 #endif
98 eff = b4 = 0;
99 }
100 }
101
102 if ((!eff)&&b4)
103 eff=0x20;
104
105 if (eff==0x8)
106 eff = b4 = 0;
107
108 // old style modules don't support last effect for:
109 // - portamento up/down
110 // - volume slide
111 if (eff==0x1&&(!b4)) eff = 0;
112 if (eff==0x2&&(!b4)) eff = 0;
113 if (eff==0xA&&(!b4)) eff = 0;
114
115 if (eff==0x5&&(!b4)) eff = 0x3;
116 if (eff==0x6&&(!b4)) eff = 0x4;
117
118 if (eff==0xC) {
119 b4 = XModule::vol64to255(b4);
120 }
121
122 if (note)
123 notenum = XModule::amigaPeriodToNote(note);
124
125 dst[0] = notenum;
126 dst[1] = ins;
127 dst[2] = eff;
128 dst[3] = b4;
129 }
130
load(XMFileBase & f,XModule * module)131 mp_sint32 LoaderDIGI::load(XMFileBase& f, XModule* module)
132 {
133 module->cleanUp();
134
135 // this will make code much easier to read
136 TXMHeader* header = &module->header;
137 TXMInstrument* instr = module->instr;
138 TXMSample* smp = module->smp;
139 TXMPattern* phead = module->phead;
140
141 // we're already out of memory here
142 if (!phead || !instr || !smp)
143 return MP_OUT_OF_MEMORY;
144
145 mp_sint32 i,j;
146 mp_ubyte buffer[31*4];
147
148 // read header
149 f.read(header->sig, 1, 16);
150 // skip 4 bytes (ule\0)
151 f.readDword();
152 // skip version string
153 f.readDword();
154 // check version
155 mp_ubyte ver = f.readByte();
156 if (ver < 0x10 ||
157 ver > 0x17)
158 return MP_LOADER_FAILED;
159 // read numchannels
160 header->channum = f.readByte();
161 // packenable
162 mp_ubyte pack = f.readByte();
163 f.read(buffer, 1, 19);
164 // read numpatterns
165 header->patnum = (mp_sword)f.readByte() + 1;
166 // read songlength
167 header->ordnum = (mp_sword)f.readByte() + 1;
168 f.read(header->ord, 1, 128);
169
170 header->insnum = 31;
171
172 f.read(buffer, 4, 31);
173
174 mp_sint32 s = 0;
175 for (i = 0; i < header->insnum; i++)
176 {
177 mp_sint32 slen = BigEndian::GET_DWORD(buffer+i*4);
178 if (slen)
179 {
180 instr[i].samp = 1;
181
182 for (j = 0; j < 120; j++)
183 instr[i].snum[j] = s;
184
185 smp[s].samplen = slen;
186 s++;
187 }
188 }
189 header->smpnum = s;
190
191 // loop starts
192 f.read(buffer, 4, 31);
193 for (i = 0; i < header->insnum; i++)
194 {
195 if (instr[i].samp)
196 {
197 s = instr[i].snum[0];
198 smp[s].loopstart = BigEndian::GET_DWORD(buffer+i*4);
199 }
200 }
201
202 // loop lengths
203 f.read(buffer, 4, 31);
204 for (i = 0; i < header->insnum; i++)
205 {
206 if (instr[i].samp)
207 {
208 s = instr[i].snum[0];
209 smp[s].looplen = BigEndian::GET_DWORD(buffer+i*4);
210 if (smp[s].looplen)
211 smp[s].type = 1;
212 }
213 }
214
215 // volumes & finetunes
216 f.read(buffer, 1, 31);
217 f.read(buffer+31, 1, 31);
218 for (i = 0; i < header->insnum; i++)
219 {
220 if (instr[i].samp)
221 {
222 s = instr[i].snum[0];
223 smp[s].vol = XModule::vol64to255(buffer[i]);
224 smp[s].pan = 0x80;
225 smp[s].flags = 1;
226 smp[s].finetune = ((mp_sbyte)buffer[i+31])*16;
227 }
228 }
229
230 f.read(header->name, 1, 32);
231
232 for (i = 0; i < header->insnum; i++)
233 {
234 f.read(instr[i].name, 1, 30);
235 if (instr[i].samp)
236 {
237 s = instr[i].snum[0];
238 memcpy(smp[s].name, instr[i].name, 30);
239 }
240 }
241
242 // read patterns
243 for (i = 0; i < header->patnum; i++)
244 {
245 phead[i].rows = 64;
246 phead[i].effnum = 1;
247 phead[i].channum = (mp_ubyte)header->channum;
248
249 phead[i].patternData = new mp_ubyte[phead[i].rows*header->channum*4];
250
251 // out of memory?
252 if (phead[i].patternData == NULL)
253 {
254 return MP_OUT_OF_MEMORY;
255 }
256
257 memset(phead[i].patternData,0,phead[i].rows*header->channum*4);
258
259 mp_sint32 pSize = 64*header->channum*4 + 64;
260 if (pack)
261 {
262 f.read(buffer, 1, 2);
263 pSize = BigEndian::GET_WORD(buffer);
264 if (pSize && pSize < 64)
265 return MP_LOADER_FAILED;
266 // read packing mask
267 f.read(buffer, 1, 64);
268 }
269 else
270 {
271 memset(buffer, 0xFF, 64);
272 }
273
274 if (!pSize)
275 continue;
276
277 mp_ubyte* pattern = new mp_ubyte[pSize-64];
278
279 if (pattern == NULL)
280 return MP_OUT_OF_MEMORY;
281
282 f.read(pattern, 1, pSize-64);
283
284 mp_ubyte* patPtr = pattern;
285
286 mp_sint32 r,c,cnt=0;
287
288 if (pack)
289 {
290 for (r=0;r<64;r++) {
291 for (c=0;c<header->channum;c++) {
292 if (buffer[r] & (1 << (7-c)))
293 {
294 convertEvent(phead[i].patternData + cnt, patPtr);
295
296 patPtr+=4;
297 }
298 cnt+=4;
299 }
300 }
301 }
302 else
303 {
304 for (c=0;c<header->channum;c++) {
305 for (r=0;r<64;r++) {
306 cnt = r*header->channum*4+c*4;
307
308 convertEvent(phead[i].patternData + cnt, patPtr);
309
310 patPtr+=4;
311 }
312 }
313 }
314
315
316 delete[] pattern;
317 }
318
319 // No for something really stupid: Pattern loop correction
320 for (mp_sint32 p = 0; p < header->patnum; p++)
321 {
322 struct Position
323 {
324 mp_sint32 row, channel;
325 };
326
327 mp_ubyte* pattern = phead[p].patternData;
328
329 Position loopStart = {-1, -1}, loopEnd = {-1, -1};
330
331 for (i = 0; i < 64; i++) {
332 for (j = 0; j < header->channum; j++)
333 {
334 mp_ubyte* slot = pattern + i*header->channum*4 + j*4;
335
336 // Loop start
337 if (slot[2] == 0x36 && !slot[3])
338 {
339 loopStart.row = i;
340 loopStart.channel = j;
341 }
342 else if (slot[2] == 0x36 && slot[3])
343 {
344 loopEnd.row = i;
345 loopEnd.channel = j;
346 }
347 }
348
349 if (loopEnd.row != -1 && loopEnd.channel != -1 &&
350 loopStart.row != -1 && loopStart.channel != -1 &&
351 loopStart.channel != loopEnd.channel)
352 {
353
354 // sanity check
355 if (loopStart.row == loopEnd.row)
356 {
357 mp_ubyte* slot = pattern + loopStart.row*header->channum*4 + loopStart.channel*4;
358 slot[2] = slot[3] = 0;
359 slot = pattern + loopEnd.row*header->channum*4 + loopEnd.channel*4;
360 slot[2] = slot[3] = 0;
361 }
362 else
363 {
364
365 for (j = 0; j < header->channum; j++)
366 {
367 mp_ubyte* slotStart = pattern + loopStart.row*header->channum*4 + j*4;
368 mp_ubyte* slotEnd = pattern + loopEnd.row*header->channum*4 + j*4;
369
370 if (!slotStart[2] && !slotEnd[2] &&
371 !slotStart[3] && !slotEnd[3])
372 {
373 mp_ubyte* slot = pattern + loopStart.row*header->channum*4 + loopStart.channel*4;
374 slotStart[2] = slot[2];
375 slotStart[3] = slot[3];
376 slot[2] = slot[3] = 0;
377 slot = pattern + loopEnd.row*header->channum*4 + loopEnd.channel*4;
378 slotEnd[2] = slot[2];
379 slotEnd[3] = slot[3];
380 slot[2] = slot[3] = 0;
381 break;
382 }
383 }
384
385 }
386
387 loopStart.row = loopStart.channel = loopEnd.row = loopEnd.channel = -1;
388
389 }
390 }
391
392 }
393
394 mp_sint32 result = module->loadModuleSamples(f);
395 if (result != MP_OK)
396 return result;
397
398 header->speed = 125;
399 header->tempo = 6;
400 header->mainvol = 255;
401
402 strcpy(header->tracker,"Digibooster");
403
404 module->setDefaultPanning();
405
406 module->postProcessSamples();
407
408 return MP_OK;
409 }
410