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 * LoaderMTM.cpp
32 * MilkyPlay Module Loader: Multitracker
33 *
34 * Warning: This is an one-by-one conversion of an assembler version ;)
35 *
36 */
37 #include "Loaders.h"
38
identifyModule(const mp_ubyte * buffer)39 const char* LoaderMTM::identifyModule(const mp_ubyte* buffer)
40 {
41 // check for .MTM module
42 if (!memcmp(buffer,"MTM\x10",4))
43 {
44 return "MTM";
45 }
46
47 return NULL;
48 }
49
load(XMFileBase & f,XModule * module)50 mp_sint32 LoaderMTM::load(XMFileBase& f, XModule* module)
51 {
52 module->cleanUp();
53
54 // this will make code much easier to read
55 TXMHeader* header = &module->header;
56 TXMInstrument* instr = module->instr;
57 TXMSample* smp = module->smp;
58 TXMPattern* phead = module->phead;
59
60 // we're already out of memory here
61 if (!phead || !instr || !smp)
62 return MP_OUT_OF_MEMORY;
63
64 f.read(header->sig, 1, 3); // read signature
65
66 if (f.readByte() != 0x10)
67 return MP_LOADER_FAILED;
68
69 f.read(header->name, 1, 20);
70
71 mp_uword numTracks = f.readWord();
72
73 header->flags = XModule::MODULE_PTNEWINSTRUMENT;
74
75 header->mainvol = 255;
76 header->tempo = 6;
77 header->speed = 125;
78 header->patnum = f.readByte() + 1;
79 header->ordnum = f.readByte() + 1;
80
81 mp_uword locf = f.readWord();
82
83 header->insnum = f.readByte();
84 header->smpnum = header->insnum;
85
86 f.readByte();
87
88 mp_sint32 numRows = f.readByte();
89 mp_sint32 trackSize = numRows*3;
90
91 header->channum = f.readByte();
92
93 mp_ubyte panPositions[32];
94 f.read(panPositions, 1, 32);
95
96 mp_sint32 i,s = 0;
97 for (i = 0; i < header->insnum; i++)
98 {
99 f.read(instr[i].name,1,22);
100
101 mp_uint32 size = f.readDword();
102 mp_uint32 loopstart = f.readDword();
103 mp_uint32 loopend = f.readDword();
104
105 mp_sbyte finetune = f.readByte()*16;
106
107 mp_ubyte volume = XModule::vol64to255(f.readByte());
108
109 /*mp_ubyte flags = */f.readByte();
110
111 if (size)
112 {
113 instr[i].samp = 1;
114
115 memcpy(smp[s].name,instr[i].name,22);
116
117 smp[s].flags = 1;
118 smp[s].samplen = size;
119 smp[s].loopstart = loopstart;
120 smp[s].looplen = loopend - loopstart;
121 smp[s].vol = volume;
122 smp[s].finetune = finetune;
123
124 for (mp_sint32 j = 0; j < 120; j++)
125 instr[i].snum[j] = s;
126
127 if ((smp[s].loopstart+smp[s].looplen)>smp[s].samplen)
128 smp[s].looplen-=(smp[s].loopstart+smp[s].looplen)-smp[s].samplen;
129
130 if (smp[s].loopstart<=2) smp[s].loopstart=0;
131 if (smp[s].looplen<=2)
132 smp[s].looplen=0;
133 else smp[s].type=1;
134
135 s++;
136 }
137
138 }
139
140 header->smpnum = s;
141
142 mp_ubyte orders[128];
143 f.read(orders, 1, 128);
144
145 for (i = 0; i < header->ordnum; i++)
146 header->ord[i] = orders[i];
147
148 mp_ubyte* tracks = new mp_ubyte[trackSize*numTracks];
149
150 if (tracks == NULL)
151 return MP_OUT_OF_MEMORY;
152
153 f.read(tracks, trackSize, numTracks);
154
155 mp_uword* trackSeq = new mp_uword[header->patnum * 32];
156
157 if (trackSeq == NULL)
158 {
159 delete[] tracks;
160 return MP_OUT_OF_MEMORY;
161 }
162
163 f.readWords(trackSeq, header->patnum * 32);
164
165 mp_uword* pTrackSeq = trackSeq;
166
167 for (i = 0; i < header->patnum;i++)
168 {
169 phead[i].rows = numRows;
170 phead[i].effnum = 1;
171 phead[i].channum = (mp_ubyte)header->channum;
172
173 phead[i].patternData = new mp_ubyte[phead[i].rows*header->channum*4];
174
175 // out of memory?
176 if (phead[i].patternData == NULL)
177 {
178 delete[] tracks;
179 delete[] trackSeq;
180 return MP_OUT_OF_MEMORY;
181 }
182
183 memset(phead[i].patternData,0,phead[i].rows*header->channum*4);
184
185 mp_sint32 c;
186 for (c=0;c<32;c++)
187 {
188 if (*pTrackSeq &&
189 (*pTrackSeq-1) < numTracks &&
190 c < header->channum)
191 {
192
193 mp_ubyte *track = (*pTrackSeq-1)*trackSize + tracks;
194
195 #ifdef VERBOSE
196 if ((*pTrackSeq-1) >= numTracks)
197 printf("piiiiep");
198 #endif
199
200 for (mp_sint32 row = 0; row < numRows; row++)
201 {
202 mp_ubyte* dstSlot = phead[i].patternData+row*phead[i].channum*4+c*4;
203
204 mp_ubyte note = track[0]>>2;
205
206 if (note)
207 note+=25;
208
209 mp_ubyte ins = ((track[0]&0x03)<<4)+(track[1]>>4);
210 mp_ubyte eff = track[1]&0x0f;
211 mp_ubyte op = track[2];
212
213 if (eff==0xE)
214 {
215 eff=(op>>4)+0x30;
216 op&=0xf;
217
218 if (eff == 0x38)
219 {
220 eff = 0x08;
221 op <<= 4;
222 }
223
224 }
225
226 if ((!eff)&&op)
227 eff=0x20;
228
229 // old style modules don't support last effect for:
230 // - portamento up/down
231 // - volume slide
232 if (eff==0x1&&(!op)) eff = 0;
233 if (eff==0x2&&(!op)) eff = 0;
234 if (eff==0xA&&(!op)) eff = 0;
235
236 if (eff==0x5&&(!op)) eff=0x3;
237 if (eff==0x6&&(!op)) eff=0x4;
238
239 if (eff==0xC)
240 op = XModule::vol64to255(op);
241
242 dstSlot[0] = note;
243 dstSlot[1] = ins;
244 dstSlot[2] = eff;
245 dstSlot[3] = op;
246
247 track+=3;
248 }
249 }
250
251 pTrackSeq++;
252
253 }
254
255 }
256
257 delete[] trackSeq;
258
259 delete[] tracks;
260
261 /*for (i = 0; i < locf; i++)
262 {
263 printf("%c",f.readByte());
264 }
265
266 printf("\n");*/
267
268 // song message
269 if (locf)
270 {
271 char* unpackedSongMessage = new char[locf];
272
273 f.read(unpackedSongMessage, 1, locf);
274
275 mp_sint32 size = locf;
276
277 // song message isn't null terminated
278 for (i = 0; i < size; i++)
279 if (unpackedSongMessage[i] == '\0') unpackedSongMessage[i] = ' ';
280
281 for (i = 0; i < size; i++)
282 {
283 char line[50];
284 memset(line, 0, sizeof(line));
285
286 if (size - i >= 39)
287 {
288 XModule::convertStr(line, unpackedSongMessage+i, 40, false);
289 i+=39;
290 }
291 else
292 {
293 XModule::convertStr(line, unpackedSongMessage+i, size-i, false);
294 i+=size-i;
295 }
296 module->addSongMessageLine(line);
297 }
298
299 delete[] unpackedSongMessage;
300
301 #ifdef VERBOSE
302 printf("%s\n",module->message);
303 #endif
304
305 }
306
307 mp_sint32 result = module->loadModuleSamples(f, XModule::ST_UNSIGNED);
308 if (result != MP_OK)
309 return result;
310
311 strcpy(header->tracker,"Multitracker");
312
313 module->setDefaultPanning();
314
315 module->postProcessSamples();
316
317 return MP_OK;
318 }
319