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 * LoaderDBM.cpp
32 * MilkyPlay Module Loader: Digibooster Pro
33 *
34 * Created by Peter Barth on 06.03.06.
35 *
36 */
37
38 #include "Loaders.h"
39
40 // to-do: improve detection
identifyModule(const mp_ubyte * buffer)41 const char* LoaderDBM::identifyModule(const mp_ubyte* buffer)
42 {
43 // check for .DTM module
44 if (memcmp(buffer,"DBM0",4))
45 return NULL;
46
47 return "DBM";
48 }
49
50 #define CLEAN_DBM \
51 { \
52 mp_uint32 i; \
53 delete[] srcIns; \
54 for (i = 0; i < header->smpnum; i++) \
55 delete[] srcSmp[i].sample; \
56 delete[] srcSmp; \
57 delete[] orderListLengths; \
58 for (i = 0; i < numSubSongs; i++) \
59 delete[] orderLists[i]; \
60 for (i = 0; i < header->patnum; i++) \
61 delete[] patterns[i]; \
62 delete[] orderLists; \
63 delete[] patterns; \
64 }
65
66
67 struct DBMInstrument
68 {
69 mp_ubyte name[30];
70 mp_uword sampnum;
71 mp_uword volume;
72 mp_uint32 finetune;
73 mp_uint32 repstart;
74 mp_uint32 replen;
75 mp_uword panning;
76 mp_uword flags;
77 // added by ME
78 mp_sint32 venvnum;
79 mp_sint32 penvnum;
80 };
81
82 struct DBMSample
83 {
84 mp_uint32 flags;
85 mp_uint32 samplen; // bit 0 set - 8 bit sample
86 // bit 1 set - 16 bit sample
87 // bit 2 set - 32 bit sample
88 mp_ubyte* sample;
89 };
90
convertDBMffects(mp_ubyte & effect,mp_ubyte & operand)91 static void convertDBMffects(mp_ubyte& effect, mp_ubyte& operand)
92 {
93 //static const char eff[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
94
95 switch (effect)
96 {
97 case 0x00:
98 if (operand)
99 effect = 0x20;
100 break;
101
102 case 0x01:
103 if ((operand & 0xF0) == 0xF0)
104 {
105 // doc says: 1Fx == fine portamento up
106 effect = 0x31;
107 operand &= 0x0F;
108 }
109 break;
110 case 0x02:
111 if ((operand & 0xF0) == 0xF0)
112 {
113 // doc says: 2Fx == fine portamento down
114 effect = 0x32;
115 operand &= 0x0F;
116 }
117 break;
118
119 case 0x03:
120 case 0x04:
121 break;
122
123 case 0x05:
124 if ((operand & 0x0F) == 0x0F)
125 {
126 // doc says: 5xF == Tone portamento+Fine Volume slide up
127 // !! unsupported !!
128 // Might be possible with MDL way of combining portamento + volume slide
129 // but with S3M volslide instead of MDL volslide
130 goto missing;
131 }
132 else if ((operand & 0xF0) == 0xF0)
133 {
134 // doc says: 5Fx == Tone portamento+Fine Volume slide down
135 // !! unsupported !!
136 // Might be possible with MDL way of combining portamento + volume slide
137 // but with S3M volslide instead of MDL volslide
138 goto missing;
139 }
140 break;
141
142 case 0x06:
143 if ((operand & 0x0F) == 0x0F)
144 {
145 // doc says: 6xF == Vibrato+Fine Volume slide up
146 // !! unsupported !!
147 // Might be possible with MDL way of combining vibrato + volume slide
148 // but with S3M volslide instead of MDL volslide
149 goto missing;
150 }
151 else if ((operand & 0xF0) == 0xF0)
152 {
153 // doc says: 6Fx == Vibrato+Fine Volume slide down
154 // !! unsupported !!
155 // Might be possible with MDL way of combining vibrato + volume slide
156 // but with S3M volslide instead of MDL volslide
157 goto missing;
158 }
159 break;
160
161 // Tremolo doesn't exist, huh?
162 case 0x07:
163 // Panning
164 case 0x08:
165 // Sample offset
166 case 0x09:
167 break;
168
169 // Volslide (S3M volslide fits best probably)
170 case 0x0A:
171 effect = 0x49;
172 break;
173
174 // Position jump
175 case 0x0B:
176 break;
177
178 // set volume
179 case 0x0C:
180 // set global volume
181 case 0x10:
182 operand = XModule::vol64to255(operand);
183 break;
184
185 // Pattern break
186 case 0x0D:
187 break;
188
189 // subcommands
190 case 0x0E:
191 {
192 effect = 0x30 + (operand >> 4);
193 operand &= 0xF;
194 switch (effect)
195 {
196 // Set filter: unsupported
197 case 0x30:
198 goto missing;
199 break;
200 // Play backwards
201 case 0x33:
202 // AMS can do that
203 effect = 0x4F;
204 operand = 1;
205 break;
206 // Turn off sound in channel?
207 // can probably be emulated with AMS set channel volume
208 // right now unsupported
209 case 0x34:
210 goto missing;
211 break;
212 // Turn on/off sound in channel?
213 // can probably be emulated with AMS set channel volume
214 // right now unsupported
215 case 0x35:
216 goto missing;
217 break;
218 // set loop/loop
219 case 0x36:
220 goto missing;
221 break;
222 // set offset for loop or what?
223 case 0x37:
224 goto missing;
225 break;
226 }
227 break;
228 }
229
230 // Pattern break
231 case 0x0F:
232 break;
233
234 case 0x11:
235 break;
236
237 // key off
238 case 0x14:
239 if (operand == 0)
240 // AMS key of at tick
241 effect = 0x51;
242 break;
243
244 // Set envelope position
245 case 0x15:
246 break;
247
248 // Sample offset slide (unsupported)
249 case 0x18:
250 goto missing;
251 break;
252
253 // set real BPM
254 case 0x1C:
255 effect = 0x52;
256 break;
257
258 // echo effects (unsupported)
259 case 0x1f:
260 case 0x20:
261 case 0x21:
262 case 0x22:
263 case 0x23:
264 goto missing;
265 break;
266
267 default:
268 #ifdef VERBOSE
269 printf("Unknown DBM effect %x with operand %x\n", effect, operand);
270 #endif
271 missing:
272 #ifdef VERBOSE
273 printf("Missing DBM effect %x with operand %x\n", effect, operand);
274 #endif
275 effect = operand = 0;
276
277 }
278
279 }
280
convertDBMEnvelope(TEnvelope & outEnv,const mp_ubyte * inEnv)281 static void convertDBMEnvelope(TEnvelope& outEnv, const mp_ubyte* inEnv)
282 {
283 memset(&outEnv, 0, sizeof(TEnvelope));
284 outEnv.type = *inEnv & 7;
285
286 #ifdef VERBOSE
287 if (*inEnv >> 3)
288 {
289 printf("Second sustain point used");
290
291 }
292 #endif
293
294 // one single point?
295 // disable envelope
296 if (!*(inEnv+1))
297 {
298 outEnv.type &= ~1;
299 return;
300 }
301
302 // DBM stores numpoints-1
303 outEnv.num = *(inEnv+1) + 1;
304 outEnv.sustain = *(inEnv+2);
305 outEnv.loops = *(inEnv+3);
306 outEnv.loope = *(inEnv+4);
307
308 inEnv+=6;
309
310 for (mp_sint32 i = 0; i < outEnv.num; i++)
311 {
312 outEnv.env[i][0] = BigEndian::GET_WORD(inEnv);
313 outEnv.env[i][1] = BigEndian::GET_WORD(inEnv+2) << 2;
314 inEnv+=4;
315 }
316 }
317
load(XMFileBase & f,XModule * module)318 mp_sint32 LoaderDBM::load(XMFileBase& f, XModule* module)
319 {
320 module->cleanUp();
321
322 // this will make code much easier to read
323 TXMHeader* header = &module->header;
324 TXMInstrument* instr = module->instr;
325 TXMSample* smp = module->smp;
326 TXMPattern* phead = module->phead;
327
328 // we're already out of memory here
329 if (!phead || !instr || !smp)
330 return MP_OUT_OF_MEMORY;
331
332 mp_sint32 i,j;
333
334 mp_uword numSubSongs = 0;
335 mp_uword** orderLists = NULL;
336 mp_uword* orderListLengths = NULL;
337 DBMInstrument* srcIns = NULL;
338 mp_ubyte** patterns = NULL;
339 DBMSample* srcSmp = NULL;
340
341 while (true)
342 {
343 mp_ubyte ID[4], buffer[4];
344
345 mp_uint32 bytesRead = f.read(ID, 4, 1);
346
347 if (bytesRead != 4)
348 break;
349
350 bytesRead = f.read(buffer, 4, 1);
351
352 if (bytesRead != 4)
353 break;
354
355 mp_uint32 chunkLen = BigEndian::GET_DWORD(buffer);
356
357 switch (BigEndian::GET_DWORD(ID))
358 {
359 case 0x44424D30: // 'DBM0'
360 memcpy(header->sig, ID, 4);
361 break;
362
363 case 0x4E414D45: // 'NAME'
364 {
365 mp_ubyte* name = new mp_ubyte[chunkLen];
366 f.read(name, 1, chunkLen);
367 memcpy(header->name, name, chunkLen > MP_MAXTEXT ? MP_MAXTEXT : chunkLen);
368 delete[] name;
369 break;
370 }
371
372 case 0x494E464F: // 'INFO'
373 f.read(buffer, 1, 2);
374 header->insnum = BigEndian::GET_WORD(buffer);
375 f.read(buffer, 1, 2);
376 header->smpnum = BigEndian::GET_WORD(buffer);
377
378 srcSmp = new DBMSample[header->smpnum];
379
380 f.read(buffer, 1, 2);
381 numSubSongs = BigEndian::GET_WORD(buffer);
382
383 // Allocate order list table
384 orderLists = new mp_uword*[numSubSongs];
385 orderListLengths = new mp_uword[numSubSongs];
386
387 f.read(buffer, 1, 2);
388 header->patnum = BigEndian::GET_WORD(buffer);
389
390 patterns = new mp_ubyte*[header->patnum];
391
392 f.read(buffer, 1, 2);
393 header->channum = BigEndian::GET_WORD(buffer);
394 break;
395
396 case 0x534F4E47: // 'SONG'
397 {
398 // Skip name
399 for (i = 0; i < numSubSongs; i++)
400 {
401 mp_ubyte name[44];
402 f.read(name, 1, 44);
403
404 f.read(buffer, 1, 2);
405 orderListLengths[i] = BigEndian::GET_WORD(buffer);
406 orderLists[i] = new mp_uword[BigEndian::GET_WORD(buffer)];
407
408 for (j = 0; j < orderListLengths[i]; j++)
409 {
410 f.read(buffer, 1, 2);
411 orderLists[i][j] = BigEndian::GET_WORD(buffer);
412 }
413 }
414 break;
415 }
416
417 case 0x494E5354: // 'INST'
418 {
419 mp_uword insNum = chunkLen / 50;
420
421 srcIns = new DBMInstrument[insNum];
422
423 for (i = 0; i < insNum; i++)
424 {
425 f.read(srcIns[i].name, 1, 30);
426 f.read(buffer, 2, 1);
427 srcIns[i].sampnum = BigEndian::GET_WORD(buffer);
428 f.read(buffer, 2, 1);
429 srcIns[i].volume = BigEndian::GET_WORD(buffer);
430 f.read(buffer, 4, 1);
431 srcIns[i].finetune = BigEndian::GET_DWORD(buffer);
432 f.read(buffer, 4, 1);
433 srcIns[i].repstart = BigEndian::GET_DWORD(buffer);
434 f.read(buffer, 4, 1);
435 srcIns[i].replen = BigEndian::GET_DWORD(buffer);
436 f.read(buffer, 2, 1);
437 srcIns[i].panning = BigEndian::GET_WORD(buffer);
438 f.read(buffer, 2, 1);
439 srcIns[i].flags = BigEndian::GET_WORD(buffer);
440
441 srcIns[i].venvnum = srcIns[i].penvnum = -1;
442 }
443 break;
444 }
445
446 case 0x50415454: // 'PATT'
447 {
448 for (i = 0; i < header->patnum; i++)
449 {
450 f.read(buffer, 2, 1);
451 phead[i].rows = BigEndian::GET_WORD(buffer);
452 f.read(buffer, 4, 1);
453 phead[i].len = BigEndian::GET_DWORD(buffer);
454
455 patterns[i] = new mp_ubyte[phead[i].len];
456 f.read(patterns[i], 1, phead[i].len);
457 }
458 break;
459 }
460
461 case 0x534D504C: // 'SMPL'
462 {
463 for (i = 0; i < header->smpnum; i++)
464 {
465 f.read(buffer, 4, 1);
466 srcSmp[i].flags = BigEndian::GET_DWORD(buffer);
467 f.read(buffer, 4, 1);
468 srcSmp[i].samplen = BigEndian::GET_DWORD(buffer);
469
470 if (srcSmp[i].flags == 1)
471 {
472 srcSmp[i].sample = new mp_ubyte[srcSmp[i].samplen];
473 module->loadSample(f, srcSmp[i].sample, srcSmp[i].samplen, srcSmp[i].samplen);
474 }
475 else if (srcSmp[i].flags == 2)
476 {
477 srcSmp[i].sample = new mp_ubyte[srcSmp[i].samplen*2];
478 module->loadSample(f, srcSmp[i].sample, srcSmp[i].samplen*2, srcSmp[i].samplen, XModule::ST_16BIT | XModule::ST_BIGENDIAN);
479 }
480 else
481 {
482 #ifdef VERBOSE
483 printf("Unsupported sample type");
484 #endif
485 }
486 }
487 break;
488 }
489
490 case 0x56454E56: // 'VENV'
491 {
492 f.read(buffer, 2, 1);
493 mp_uword numEnvelopes = BigEndian::GET_WORD(buffer);
494 for (i = 0; i < numEnvelopes; i++)
495 {
496 f.read(buffer, 2, 1);
497 mp_uword index = BigEndian::GET_WORD(buffer);
498
499 if (index)
500 srcIns[index-1].venvnum = module->numVEnvs;
501
502 mp_ubyte env[134];
503 f.read(env, 1, 134);
504
505 TEnvelope venv;
506 convertDBMEnvelope(venv, env);
507
508 if (!module->addVolumeEnvelope(venv))
509 {
510 CLEAN_DBM;
511 return MP_OUT_OF_MEMORY;
512 }
513 }
514 break;
515 }
516
517 case 0x50454E56: // 'PENV'
518 {
519 f.read(buffer, 2, 1);
520 mp_uword numEnvelopes = BigEndian::GET_WORD(buffer);
521 for (i = 0; i < numEnvelopes; i++)
522 {
523 f.read(buffer, 2, 1);
524 mp_uword index = BigEndian::GET_WORD(buffer);
525
526 if (index)
527 srcIns[index-1].penvnum = module->numPEnvs;
528
529 mp_ubyte env[134];
530 f.read(env, 1, 134);
531
532 TEnvelope penv;
533 convertDBMEnvelope(penv, env);
534
535 if (!module->addPanningEnvelope(penv))
536 {
537 CLEAN_DBM;
538 return MP_OUT_OF_MEMORY;
539 }
540 }
541 break;
542 }
543
544 default:
545 f.seekWithBaseOffset(f.posWithBaseOffset() + chunkLen);
546
547 }
548 }
549
550 if (!(orderListLengths && srcIns && patterns && srcSmp))
551 return MP_LOADER_FAILED;
552
553 // Convert orderlist, subsongs are not supported yet
554 j = 0;
555 for (i = 0; i < orderListLengths[j]; i++)
556 {
557 if (i < 256)
558 header->ord[i] = (mp_ubyte)orderLists[j][i];
559 }
560
561 header->ordnum = orderListLengths[j];
562
563 header->mainvol = 255;
564 header->speed = 125;
565 header->tempo = 6;
566 header->flags = XModule::MODULE_OLDPTINSTRUMENTCHANGE | XModule::MODULE_PTNEWINSTRUMENT;
567 header->volenvnum = module->numVEnvs;
568 header->panenvnum = module->numPEnvs;
569
570 // Convert patterns
571 for (i = 0; i < header->patnum; i++)
572 {
573 phead[i].effnum = 2;
574 phead[i].channum = (mp_ubyte)header->channum;
575
576 const mp_sint32 bps = phead[i].effnum*2+2;
577
578 phead[i].patternData = new mp_ubyte[phead[i].rows*header->channum*bps];
579
580 // out of memory?
581 if (phead[i].patternData == NULL)
582 {
583 CLEAN_DBM;
584 return MP_OUT_OF_MEMORY;
585 }
586
587 memset(phead[i].patternData, 0, phead[i].rows*header->channum*bps);
588
589 mp_uint32 currentRow = 0;
590
591 j = 0;
592
593 mp_ubyte* src = patterns[i];
594
595 while (j < (signed)phead[i].len && currentRow < phead[i].rows)
596 {
597 mp_ubyte pack = src[j];
598 j++;
599 if (!pack)
600 currentRow++;
601 else
602 {
603 mp_ubyte note = 0, ins = 0;
604 mp_ubyte eff1 = 0, op1 = 0, eff2 = 0, op2 = 0;
605
606 mp_ubyte channel = pack-1;
607
608 pack = src[j];
609 j++;
610
611 // Note present?
612 if (pack & 0x01)
613 {
614 if (src[j] == 0x1F)
615 note = XModule::NOTE_OFF;
616 else
617 note = (src[j] >> 4) * 12 + ((src[j] & 0xF)+1);
618 j++;
619 }
620 // Instrument present?
621 if (pack & 0x02)
622 {
623 ins = src[j];
624 j++;
625 }
626 // Effect 1 present?
627 if (pack & 0x04)
628 {
629 eff1 = src[j];
630 j++;
631 }
632 // Operand 1 present?
633 if (pack & 0x08)
634 {
635 op1 = src[j];
636 j++;
637 }
638 // Effect 2 present?
639 if (pack & 0x10)
640 {
641 eff2 = src[j];
642 j++;
643 }
644 // Operand 1 present?
645 if (pack & 0x20)
646 {
647 op2 = src[j];
648 j++;
649 }
650
651 convertDBMffects(eff1, op1);
652 convertDBMffects(eff2, op2);
653
654 mp_ubyte* dstSlot = phead[i].patternData +
655 currentRow * header->channum*bps + channel*bps;
656
657 *dstSlot++ = note;
658 *dstSlot++ = ins;
659 *dstSlot++ = eff1;
660 *dstSlot++ = op1;
661 *dstSlot++ = eff2;
662 *dstSlot++ = op2;
663 }
664 }
665
666 }
667
668 // convert instrument data
669 for (i = 0; i < header->insnum; i++)
670 {
671 memcpy(instr[i].name, srcIns[i].name, MP_MAXTEXT);
672 for (j = 0; j < 120; j++)
673 instr[i].snum[j] = i;
674
675 j = srcIns[i].sampnum;
676
677 if (j && j <= header->smpnum)
678 {
679 j--;
680 if (srcSmp[j].samplen)
681 {
682 instr[i].samp = 1;
683
684 smp[i].flags = 1 | (srcIns[i].panning ? 2 : 0);
685 smp[i].pan = (srcIns[i].panning ? srcIns[i].panning - 1 : 0x80);
686 smp[i].vol = XModule::vol64to255(srcIns[i].volume);
687
688 smp[i].samplen = srcSmp[j].samplen;
689
690 if (srcSmp[j].flags == 1)
691 {
692 smp[i].sample = (mp_sbyte*)module->allocSampleMem(smp[i].samplen);
693 memcpy(smp[i].sample, srcSmp[j].sample, smp[i].samplen);
694 }
695 else if (srcSmp[j].flags == 2)
696 {
697 smp[i].sample = (mp_sbyte*)module->allocSampleMem(smp[i].samplen*2);
698 memcpy(smp[i].sample, srcSmp[j].sample, smp[i].samplen*2);
699 smp[i].type |= 16;
700 }
701
702 XModule::convertc4spd(srcIns[i].finetune, &smp[i].finetune, &smp[i].relnote);
703
704 smp[i].loopstart = srcIns[i].repstart;
705 smp[i].looplen = srcIns[i].replen;
706
707 if (((srcIns[i].flags & 3) == 1) && smp[i].looplen)
708 smp[i].type |= 1;
709 else if (((srcIns[i].flags & 2) == 2) && smp[i].looplen)
710 smp[i].type |= 2;
711
712 if (srcIns[i].venvnum >= 0)
713 smp[i].venvnum = srcIns[i].venvnum+1;
714 if (srcIns[i].penvnum >= 0)
715 smp[i].penvnum = srcIns[i].penvnum+1;
716 }
717 }
718 }
719
720 CLEAN_DBM;
721
722 header->smpnum = header->insnum;
723
724 strcpy(header->tracker,"Digibooster Pro");
725
726 module->setDefaultPanning();
727
728 module->postProcessSamples();
729
730 return MP_OK;
731 }
732