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  *  ExporterXM.cpp
32  *  MilkyPlay XM writer (trying hard to export something useful)
33  *
34  *  --------------------------------
35  *			Version History:
36  *  --------------------------------
37  *  26/03/06: PLM Far position jump fix & effects are relocated to other channels if possible
38  *  01/01/06: Happy new year ;) MilkyTracker XMs are now even smaller than FT2 XMs
39  *  02/12/05: Fixed problems with last operand restoration for S3M and MDL commands. VERY SLOW(!!) but working
40  *  06/02/05: Added simulation of multitracker behaviour with FT2 features
41  *  05/02/05: Added simulation of protracker behaviour with FT2 features
42  *  07/12/04: Writes all other instrument related stuff too (envelopes, auto-vibrato etc.)
43  *  06/12/04: Added sample relative note remapper when note range exceeds regular XM note range (RIGHT.PTM)
44  *  05/12/04: First acceptable results with one-effect modules (.MOD / .MTM)
45  *  04/12/04: Started work
46  *
47  */
48 #include "MilkyPlay.h"
49 
50 #ifdef VERBOSE
51 	#include "stdio.h"
52 #endif
53 
54 struct TWorkBuffers
55 {
56 	mp_sint32 noteRangeRemapper[256];
57 	mp_ubyte lastArpeggio[256];
58 	mp_ubyte lastVolSlide[256];
59 	mp_ubyte lastGVolSlide[256];
60 	mp_ubyte lastPorta[256];
61 	mp_ubyte lastTempoSlide[256];
62 	mp_sint32 globalVolume;
63 	mp_sint32 bpm, baseBpm, speed;
64 
65 	mp_ubyte lastIns[256];
66 	mp_ubyte lastNote[256];
67 
clearBuffersTWorkBuffers68 	void clearBuffers()
69 	{
70 		memset(lastArpeggio, 0, sizeof(lastArpeggio));
71 		memset(lastVolSlide, 0, sizeof(lastVolSlide));
72 		memset(lastGVolSlide, 0, sizeof(lastGVolSlide));
73 		memset(lastPorta, 0, sizeof(lastPorta));
74 		memset(lastTempoSlide, 0, sizeof(lastTempoSlide));
75 		memset(lastIns, 0, sizeof(lastIns));
76 		memset(lastNote, 0, sizeof(lastNote));
77 		globalVolume = 64;
78 		baseBpm = 125;
79 		bpm = 125;
80 		speed = 6;
81 	}
82 
TWorkBuffersTWorkBuffers83 	TWorkBuffers()
84 	{
85 		clearBuffers();
86 
87 		memset(noteRangeRemapper, 0, sizeof(noteRangeRemapper));
88 	}
89 };
90 
convertEffect(mp_ubyte effIn,mp_ubyte opIn,mp_ubyte & effOut,mp_ubyte & opOut,mp_sint32 curChan,TWorkBuffers & workBuffers,bool convertITTempoSlides)91 static void convertEffect(mp_ubyte effIn, mp_ubyte opIn, mp_ubyte& effOut, mp_ubyte& opOut, mp_sint32 curChan, TWorkBuffers& workBuffers, bool convertITTempoSlides)
92 {
93 	mp_ubyte* lastArpeggio = workBuffers.lastArpeggio;
94 	mp_ubyte* lastVolSlide = workBuffers.lastVolSlide;
95 	mp_ubyte* lastGVolSlide = workBuffers.lastGVolSlide;
96 	mp_ubyte* lastPorta = workBuffers.lastPorta;
97 	mp_ubyte* lastTempoSlide = workBuffers.lastTempoSlide;
98 
99 	effOut = opOut = 0;
100 
101 	// Protracker commands
102 	if (effIn > 0 && effIn <= 0x11)
103 	{
104 		effOut = effIn;
105 		opOut = opIn;
106 
107 		if (effIn == 0x0C || effIn == 0x10)
108 			opOut = (mp_ubyte)(((mp_sint32)opOut*64)/255);
109 
110 		if (effIn == 0x10)
111 			workBuffers.globalVolume = (mp_ubyte)(((mp_sint32)opOut*64)/255);
112 
113 		// Cope with set BPM in case we're having a DBM "set real BPM command"
114 		if (effIn == 0x0f && opIn >= 32)
115 		{
116 			// real BPM is not the default value => recalculate BPM
117 			if (workBuffers.baseBpm != 125)
118 			{
119 				// First store current BPM
120 				workBuffers.bpm = opIn;
121 				// Now calculate new BPM (see DBM player source)
122 				mp_sint32 realCiaTempo = (workBuffers.bpm * (workBuffers.baseBpm << 8) / 125) >> 8;
123 				// clip if necessary
124 				if (realCiaTempo > 255)
125 					realCiaTempo = 255;
126 				if (realCiaTempo < 32)
127 					realCiaTempo = 32;
128 				// This is our new set BPM
129 				opOut = realCiaTempo;
130 			}
131 		}
132 
133 	}
134 	// set envelope position
135 	else if (effIn == 0x14 || effIn == 0x51)
136 	{
137 		effOut = 0x14;
138 		opOut = opIn;
139 	}
140 	// set envelope position
141 	else if (effIn == 0x15)
142 	{
143 		effOut = effIn;
144 		opOut = opIn;
145 	}
146 	// set tempo
147 	else if (effIn == 0x16)
148 	{
149 		if (opIn >= 32)
150 		{
151 			// First store current BPM
152 			workBuffers.bpm = opIn;
153 			// Cope with set BPM in case we're having a DBM "set real BPM command"
154 			if (workBuffers.baseBpm != 125)
155 			{
156 				// Now calculate new BPM (see DBM player source)
157 				mp_sint32 realCiaTempo = (workBuffers.bpm * (workBuffers.baseBpm << 8) / 125) >> 8;
158 				// clip
159 				if (realCiaTempo > 255)
160 					realCiaTempo = 255;
161 				if (realCiaTempo < 32)
162 					realCiaTempo = 32;
163 				// new effect 0xF with new BPM
164 				effOut = 0x0F;
165 				opOut = realCiaTempo;
166 			}
167 			else
168 			{
169 				if (opIn < 32) opIn = 32;
170 				effOut = 0x0F;
171 				opOut = opIn;
172 			}
173 		}
174 		else if (convertITTempoSlides)
175 		{
176 			if (opIn) lastTempoSlide[curChan] = opIn;
177 
178 			if (lastTempoSlide[curChan])
179 			{
180 				mp_ubyte y = lastTempoSlide[curChan]>>4;
181 				mp_ubyte x = lastTempoSlide[curChan]&0xf;
182 
183 				// tempo slide up
184 				if (y)
185 				{
186 					effOut = 0x0F;
187 					workBuffers.bpm+=x*(workBuffers.speed-1);
188 					if (workBuffers.bpm > 255)
189 						workBuffers.bpm = 255;
190 					opOut = workBuffers.bpm;
191 				}
192 				// tempo slide down
193 				else
194 				{
195 					effOut = 0xF;
196 					workBuffers.bpm-=x*(workBuffers.speed-1);
197 					if (workBuffers.bpm < 32)
198 						workBuffers.bpm = 32;
199 					opOut = workBuffers.bpm;
200 				}
201 			}
202 		}
203 	}
204 	// Panning slide / Multi retrig / tremor
205 	else if (effIn == 0x19 || effIn == 0x1B || effIn == 0x1D)
206 	{
207 		effOut = effIn;
208 		opOut = opIn;
209 	}
210 	// set speed
211 	else if (effIn == 0x1C)
212 	{
213 		if (opIn)
214 		{
215 			if (opIn > 31) opIn = 31;
216 			effOut = 0x0F;
217 			opOut = opIn;
218 		}
219 	}
220 	// MDL set sample offset
221 	else if (effIn == 0x1F)
222 	{
223 		effOut = 0x09;
224 		opOut = opIn;
225 	}
226 	// PLM position jump
227 	else if (effIn == 0x2B)
228 	{
229 		effOut = 0x0B;
230 		opOut = opIn;
231 	}
232 	// Protracker subcommands (most likely)
233 	else if (effIn >= 0x30 && effIn <= 0x3F)
234 	{
235 		effOut = 0x0E;
236 		opOut = ((effIn-0x30)<<4)+(opIn&0xF);
237 	}
238 	// arpeggio
239 	else if (effIn == 0x20)
240 	{
241 		if (!opIn) opIn = lastArpeggio[curChan];
242 
243 		if (opIn)
244 		{
245 			effOut = 0;
246 			opOut = opIn;
247 			lastArpeggio[curChan] = opIn;
248 		}
249 
250 	}
251 	// extra fine porta commands
252 	else if (effIn == 0x41)
253 	{
254 		effOut = 0x21;
255 		opOut = 0x10 + (opIn <= 0xf ? opIn&0xF : 0xF);
256 	}
257 	else if (effIn == 0x42)
258 	{
259 		effOut = 0x21;
260 		opOut = 0x20 + (opIn <= 0xf ? opIn&0xF : 0xF);
261 	}
262 	// MDL porta up
263 	else if (effIn == 0x43)
264 	{
265 		if (opIn) lastPorta[curChan] = opIn;
266 
267 		if (lastPorta[curChan] >= 0xE0) {
268 			mp_ubyte y = lastPorta[curChan]>>4;
269 			mp_ubyte x = lastPorta[curChan]&0xf;
270 			switch (y) {
271 				case 0xF:
272 					effOut = 0xE;
273 					opOut = 0x10 + x;
274 					break;
275 				case 0xE:
276 					effOut = 0x21;
277 					opOut = 0x10 + (x>>1);
278 					break;
279 			}
280 		}
281 		else if (lastPorta[curChan])
282 		{
283 			effOut = 0x1;
284 			opOut = lastPorta[curChan];
285 		}
286 	}
287 	// MDL porta down
288 	else if (effIn == 0x44)
289 	{
290 		if (opIn) lastPorta[curChan] = opIn;
291 
292 		if (lastPorta[curChan] >= 0xE0) {
293 			mp_ubyte y = lastPorta[curChan] >> 4;
294 			mp_ubyte x = lastPorta[curChan] & 0xf;
295 			switch (y) {
296 				case 0xF:
297 					effOut = 0xE;
298 					opOut = 0x20 + x;
299 					break;
300 				case 0xE:
301 					effOut = 0x21;
302 					opOut = 0x20 + (x>>1);
303 					break;
304 			}
305 		}
306 		else if (lastPorta[curChan])
307 		{
308 			effOut = 0x2;
309 			opOut = lastPorta[curChan];
310 		}
311 	}
312 	// MDL volslide up
313 	else if (effIn == 0x45)
314 	{
315 		if (opIn) lastVolSlide[curChan] = opIn;
316 
317 		if (lastVolSlide[curChan] >= 0xE0) {
318 			mp_ubyte y = lastVolSlide[curChan]>>4;
319 			mp_ubyte x = lastVolSlide[curChan]&0xf;
320 			switch (y) {
321 				case 0xF:
322 					effOut = 0xE;
323 					opOut = 0xA0 + x;
324 					break;
325 				case 0xE:
326 					effOut = 0xE;
327 					opOut = 0xA0 + (x>>2);
328 					break;
329 			}
330 		}
331 		else if (lastVolSlide[curChan])
332 		{
333 			effOut = 0xA;
334 			opOut = (lastVolSlide[curChan]>>2) <= 0xF ? (lastVolSlide[curChan]>>2)<<4 : 0xF0;
335 		}
336 	}
337 	// MDL volslide down
338 	else if (effIn == 0x46)
339 	{
340 		if (opIn) lastVolSlide[curChan] = opIn;
341 
342 		if (lastVolSlide[curChan] >= 0xE0) {
343 			mp_ubyte y = lastVolSlide[curChan] >> 4;
344 			mp_ubyte x = lastVolSlide[curChan] & 0xf;
345 			switch (y) {
346 				case 0xF:
347 					effOut = 0xE;
348 					opOut = 0xB0 + x;
349 					break;
350 				case 0xE:
351 					effOut = 0xE;
352 					opOut = 0xB0 + (x>>2);
353 					break;
354 			}
355 		}
356 		else if (lastVolSlide[curChan])
357 		{
358 			effOut = 0xA;
359 			opOut = (lastVolSlide[curChan]>>2) <= 0xF ? (lastVolSlide[curChan]>>2) : 0xF;
360 		}
361 	}
362 	// S3M porta up
363 	else if (effIn == 0x47)
364 	{
365 		if (opIn) lastPorta[curChan] = opIn;
366 		if (lastPorta[curChan] >= 0xE0) {
367 			mp_ubyte y = lastPorta[curChan] >> 4;
368 			mp_ubyte x = lastPorta[curChan] & 0xf;
369 			switch (y) {
370 				case 0xF:
371 					effOut = 0xE;
372 					opOut = 0x10 + x;
373 					break;
374 				case 0xE:
375 					effOut = 0x21;
376 					opOut = 0x10 + x;
377 					break;
378 			}
379 		}
380 		else if (lastPorta[curChan])
381 		{
382 			effOut = 0x1;
383 			opOut = lastPorta[curChan];
384 		}
385 	}
386 	// S3M porta down
387 	else if (effIn == 0x48)
388 	{
389 		if (opIn) lastPorta[curChan] = opIn;
390 		if (lastPorta[curChan] >= 0xE0) {
391 			mp_ubyte y = lastPorta[curChan] >> 4;
392 			mp_ubyte x = lastPorta[curChan] & 0xf;
393 			switch (y) {
394 				case 0xF:
395 					effOut = 0xE;
396 					opOut = 0x20 + x;
397 					break;
398 				case 0xE:
399 					effOut = 0x21;
400 					opOut = 0x20 + x;
401 					break;
402 			}
403 		}
404 		else if (lastPorta[curChan])
405 		{
406 			effOut = 0x2;
407 			opOut = lastPorta[curChan];
408 		}
409 	}
410 	// S3M volslide
411 	else if (effIn == 0x49)
412 	{
413 		if (opIn) lastVolSlide[curChan] = opIn;
414 
415 		if (lastVolSlide[curChan])
416 		{
417 			mp_ubyte y = lastVolSlide[curChan]>>4;
418 			mp_ubyte x = lastVolSlide[curChan]&0xf;
419 
420 			if (!(x == 0xF && y)&&!(y == 0xF && x))
421 			{
422 				if (x && y) x = 0;
423 
424 				if (y)
425 				{
426 					effOut = 0xA;
427 					opOut = y<<4;
428 				}
429 				else if (x)
430 				{
431 					effOut = 0xA;
432 					opOut = x;
433 				}
434 
435 			}
436 			else
437 			{
438 				if (!(x==0x0F && !y) && !(y==0x0F && !x))
439 				{
440 					if (x==0x0F)
441 					{
442 						effOut = 0xE;
443 						opOut = 0xA0+y;
444 					}
445 					else if (y==0x0F)
446 					{
447 						effOut = 0xE;
448 						opOut = 0xB0+x;
449 					}
450 				}
451 			}
452 		}
453 	}
454 	// PSM fine volslide up
455 	else if (effIn == 0x4B)
456 	{
457 		effOut = 0x0E;
458 		opOut = opIn>>2;
459 		if (opOut>0xF) opOut=0x0F;
460 		opOut+=0xA0;
461 	}
462 	// PSM fine volslide down
463 	else if (effIn == 0x4C)
464 	{
465 		effOut = 0x0E;
466 		opOut = opIn>>2;
467 		if (opOut>0xF) opOut=0x0F;
468 		opOut+=0xB0;
469 	}
470 	// PSM porta up
471 	else if (effIn == 0x4D)
472 	{
473 		effOut = 0x01;
474 		opOut = opIn>>2;
475 	}
476 	// PSM porta down
477 	else if (effIn == 0x4E)
478 	{
479 		effOut = 0x02;
480 		opOut = opIn>>2;
481 	}
482 	// "S3M" global volslide, this is an IT/MODPLUG feature
483 	else if (effIn == 0x59)
484 	{
485 		if (opIn) lastGVolSlide[curChan] = opIn;
486 
487 		if (lastGVolSlide[curChan])
488 		{
489 			mp_ubyte y = lastGVolSlide[curChan]>>4;
490 			mp_ubyte x = lastGVolSlide[curChan]&0xf;
491 
492 			if (!(x == 0xF && y)&&!(y == 0xF && x))
493 			{
494 				if (x && y) x = 0;
495 
496 				if (y)
497 				{
498 					effOut = 0x11;
499 					opOut = y<<4;
500 					workBuffers.globalVolume+=y*(workBuffers.speed-1);
501 					if (workBuffers.globalVolume > 64)
502 						workBuffers.globalVolume = 64;
503 				}
504 				else if (x)
505 				{
506 					effOut = 0x11;
507 					opOut = x;
508 					workBuffers.globalVolume-=x*(workBuffers.speed-1);
509 					if (workBuffers.globalVolume < 0)
510 						workBuffers.globalVolume = 0;
511 				}
512 
513 			}
514 			else
515 			{
516 				// SUCKS
517 				if (!(x==0x0F && !y) && !(y==0x0F && !x))
518 				{
519 					if (x==0x0F)
520 					{
521 						workBuffers.globalVolume += y;
522 						if (workBuffers.globalVolume > 64)
523 							workBuffers.globalVolume = 64;
524 						effOut = 0x10;
525 						opOut = (mp_ubyte)workBuffers.globalVolume;
526 					}
527 					else if (y==0x0F)
528 					{
529 						workBuffers.globalVolume -= x;
530 						if (workBuffers.globalVolume < 0)
531 							workBuffers.globalVolume = 0;
532 						effOut = 0x10;
533 						opOut = (mp_ubyte)workBuffers.globalVolume;
534 					}
535 				}
536 			}
537 		}
538 	}
539 	// set digibooster real BPM
540 	else if (effIn == 0x52)
541 	{
542 		// store new BPM base
543 		workBuffers.baseBpm = opIn;
544 		// if it's not the default value recalculate BPM
545 		if (workBuffers.baseBpm != 125)
546 		{
547 			// see digibooster pro player source
548 			mp_sint32 realCiaTempo = (workBuffers.bpm * (workBuffers.baseBpm << 8) / 125) >> 8;
549 			// clip if necessary
550 			if (realCiaTempo > 255)
551 				realCiaTempo = 255;
552 			if (realCiaTempo < 32)
553 				realCiaTempo = 32;
554 			// write new command: 0xF with new operand
555 			effOut = 0x0F;
556 			opOut = realCiaTempo;
557 		}
558 	}
559 	// FAR/669 (effects are really different, conversion doesn't make much sense)
560 	else if (effIn == 0x70)
561 	{
562 		switch (opIn>>4)
563 		{
564 			case 0x0f:
565 				effOut = 0xf;
566 				opOut = opIn&0xf;
567 				break;
568 		}
569 	}
570 	else if (effIn)
571 	{
572 #ifdef VERBOSE
573 		printf("Missing effect %i, %i\n", effIn, opIn);
574 #endif
575 	}
576 }
577 
578 // convert FT2 compatible effect to volumn column effect if possible
convertToVolume(mp_ubyte eff,mp_ubyte op)579 static mp_ubyte convertToVolume(mp_ubyte eff, mp_ubyte op)
580 {
581 
582 	mp_ubyte vol = 0;
583 
584 	/*if (eff && eff != 0x0C)
585 	{
586 		printf("%i, %i\n", eff, op);
587 	}*/
588 
589 	// set volume
590 	if (eff == 0x0C)
591 	{
592 		vol = 0x10 + op;
593 	}
594 	// volslide
595 	else if (eff == 0x0A)
596 	{
597 
598 		// use last operand?
599 		if (!op)
600 		{
601 			vol = 0x60;
602 		}
603 		// volslide down
604 		else if (op & 0xF)
605 		{
606 			vol = 0x60 + (op&0xF);
607 		}
608 		// volslide up
609 		else if (op >> 4)
610 		{
611 			vol = 0x70 + (op>>4);
612 		}
613 
614 	}
615 	// extra fine volslide up
616 	else if (eff == 0xE && ((op>>4)==0xA))
617 	{
618 		vol = 0x90 + (op & 0xF);
619 	}
620 	// extra fine volslide down
621 	else if (eff == 0xE && ((op>>4)==0xB))
622 	{
623 		vol = 0x80 + (op & 0xF);
624 	}
625 	// extra vibrato
626 	else if (eff == 0x4)
627 	{
628 		if ((op>>4) && !(op&0xF))
629 		{
630 			vol = 0xA0 + (op>>4);
631 		}
632 		else if (!(op>>4)/* && (op&0xF)*/)
633 		{
634 			vol = 0xB0 + op;
635 		}
636 	}
637 	// set panning
638 	else if (eff == 0x8)
639 	{
640 		vol = 0xC0 + (op>>4);
641 	}
642 	// panning slide
643 	else if (eff == 0x19)
644 	{
645 		// use last operand?
646 		if (!op)
647 		{
648 			vol = 0xD0;
649 		}
650 		// panning slide left
651 		else if (op & 0xF)
652 		{
653 			vol = 0xD0 + (op&0xF);
654 		}
655 		// panning slide right
656 		else if (op >> 4)
657 		{
658 			vol = 0xE0 + (op>>4);
659 		}
660 	}
661 	// porta to note
662 	else if (eff == 0x03)
663 	{
664 		vol = 0xF0 + (op>>4);
665 	}
666 
667 	return vol;
668 }
669 
670 // Convert a bunch of effects (srcSlot with numEffects)
671 // into volume, eff and op (XM operands)
672 // curChan is the current channel
673 // workBuffers holds the last effect operands while processing
674 // effectBuffer holds a bunch (numEffectsInBuffer) of remaining
675 // effects from the  last columns which might be allowed to go
676 // into another channel
677 // swapBuffer must be at least of effectBuffer size
convertEffects(mp_ubyte * srcSlot,mp_sint32 numEffects,mp_ubyte & volume,mp_ubyte & eff,mp_ubyte & op,mp_sint32 curChan,TWorkBuffers & workBuffers,mp_ubyte * effectBuffer,mp_sint32 & numEffectsInBuffer,mp_ubyte * swapBuffer,bool convertITTempoSlides)678 static void convertEffects(mp_ubyte* srcSlot,
679 						   mp_sint32 numEffects,
680 						   mp_ubyte& volume,
681 						   mp_ubyte& eff,
682 						   mp_ubyte& op,
683 						   mp_sint32 curChan,
684 						   TWorkBuffers& workBuffers,
685 						   mp_ubyte* effectBuffer,
686 						   mp_sint32& numEffectsInBuffer,
687 						   mp_ubyte* swapBuffer,
688 						   bool convertITTempoSlides)
689 {
690 	mp_sint32 i;
691 
692 	// If there is only one effect this goes into the effect column
693 	if (numEffects == 1)
694 	{
695 		volume = 0;
696 
697 		convertEffect(srcSlot[2], srcSlot[3], eff, op, curChan, workBuffers, convertITTempoSlides);
698 	}
699 	else if (numEffects >= 2)
700 	{
701 		mp_sint32 oldNum = numEffects;
702 		numEffects+=numEffectsInBuffer;
703 		mp_ubyte* effects = swapBuffer;
704 
705 		// Convert effects to be FT2 compatible
706 		// Result will be written in effects
707 		for (i = 0; i < oldNum; i++)
708 		{
709 			effects[i*2] = effects[i*2+1] = 0;
710 			convertEffect(srcSlot[2+i*2], srcSlot[2+i*2+1], effects[i*2], effects[i*2+1], curChan, workBuffers, convertITTempoSlides);
711 		}
712 		// Append replacable effects which are left from other columns
713 		for (i = 0; i < numEffectsInBuffer; i++)
714 		{
715 			mp_uint32 j = oldNum + i;
716 			effects[j*2] = effectBuffer[i*2];
717 			effects[j*2+1] = effectBuffer[i*2+1];
718 		}
719 
720 		// Now "effects" contains all effects+operands
721 		// We try to find a home for them
722 		for (i = 0; i < numEffects; i++)
723 		{
724 			// could be MDL portamento + volslide
725 			if (numEffects >= 3 &&
726 				effects[i*2] == 0x3 &&
727 				effects[i*2+1] == 0)
728 			{
729 				for (mp_sint32 j = 0; j < numEffects; j++)
730 				{
731 					if (effects[j*2] == 0xA &&
732 						effects[j*2+1] != 0)
733 					{
734 						effects[i*2] = 0x5;
735 						effects[i*2+1] = effects[j*2+1];
736 
737 						// clear out
738 						effects[j*2] = 0;
739 						effects[j*2+1] = 0;
740 					}
741 				}
742 			}
743 			// could be MDL vibrato + volslide
744 			if (numEffects >= 3 &&
745 				effects[i*2] == 0x4 &&
746 				effects[i*2+1] == 0)
747 			{
748 				for (mp_sint32 j = 0; j < numEffects; j++)
749 				{
750 					if (effects[j*2] == 0xA &&
751 						effects[j*2+1] != 0)
752 					{
753 						effects[i*2] = 0x6;
754 						effects[i*2+1] = effects[j*2+1];
755 
756 						// clear out
757 						effects[j*2] = 0;
758 						effects[j*2+1] = 0;
759 					}
760 				}
761 			}
762 		}
763 
764 		volume = 0;
765 		eff = 0;
766 		op = 0;
767 
768 		for (i = 0; i < numEffects; i++)
769 		{
770 			// Effect nr. 1 => try to stuff into volume column first
771 			if (i == 0)
772 			{
773 				// If this is a portamento to note command and it's
774 				// volume column compatible we'll place it in the
775 				// volume column
776 				bool notePortaNotVolumeCompatible = ((effects[i*2] == 0x03) && (effects[i*2+1]&0xF));
777 
778 				if (convertToVolume(effects[i*2], effects[i*2+1]) && !volume && !notePortaNotVolumeCompatible)
779 				{
780 					volume = convertToVolume(effects[i*2], effects[i*2+1]);
781 					// clear out
782 					effects[i*2] = effects[i*2+1] = 0;
783 				}
784 				// didn't work
785 				else if ((effects[i*2] || effects[i*2+1]) && (!eff && !op))
786 				{
787 					eff = effects[i*2];
788 					op = effects[i*2+1];
789 					// clear out
790 					effects[i*2] = effects[i*2+1] = 0;
791 				}
792 			}
793 			// for the rest of the effects, try to find
794 			// free space, take effect column first, volume column secondly
795 			else
796 			{
797 				if ((effects[i*2] || effects[i*2+1]) && (!eff && !op))
798 				{
799 					eff = effects[i*2];
800 					op = effects[i*2+1];
801 					// clear out
802 					effects[i*2] = effects[i*2+1] = 0;
803 				}
804 				else if (convertToVolume(effects[i*2], effects[i*2+1]) && !volume)
805 				{
806 					volume = convertToVolume(effects[i*2], effects[i*2+1]);
807 					// clear out
808 					effects[i*2] = effects[i*2+1] = 0;
809 				}
810 			}
811 
812 		}
813 
814 		mp_uint32 numOutEffs = 0;
815 		// Scan what's left and sort out effects which are not allowed to go into another channel
816 		for (i = 0; i < numEffects; i++)
817 		{
818 			switch (effects[i*2])
819 			{
820 				case 0x0B:
821 				case 0x0D:
822 
823 				case 0x0E:
824 					switch (effects[i*2+1] >> 4)
825 					{
826 						case 0xE:
827 							goto takeEffect;
828 					}
829 					break;
830 
831 				case 0x0F:
832 takeEffect:
833 					effectBuffer[numOutEffs*2] = effects[i*2];
834 					effectBuffer[numOutEffs*2+1] = effects[i*2+1];
835 					numOutEffs++;
836 					break;
837 			}
838 		}
839 
840 		numEffectsInBuffer = numOutEffs;
841 
842 		//if (numOutEffs)
843 		//	printf("%i\n", numOutEffs);
844 
845 	}
846 
847 }
848 
fillWorkBuffers(const XModule * module,mp_uint32 orderListIndex,TWorkBuffers & workBuffers)849 static void fillWorkBuffers(const XModule* module, mp_uint32 orderListIndex, TWorkBuffers& workBuffers)
850 {
851 	workBuffers.clearBuffers();
852 
853 	mp_ubyte* lastArpeggio = workBuffers.lastArpeggio;
854 	mp_ubyte* lastVolSlide = workBuffers.lastVolSlide;
855 	mp_ubyte* lastGVolSlide = workBuffers.lastGVolSlide;
856 	mp_ubyte* lastPorta = workBuffers.lastPorta;
857 	mp_ubyte* lastNote = workBuffers.lastNote;
858 	mp_ubyte* lastIns = workBuffers.lastIns;
859 	mp_ubyte* lastTempoSlide = workBuffers.lastTempoSlide;
860 
861 	for (mp_uint32 orderIndex = 0; orderIndex < orderListIndex; orderIndex++)
862 	{
863 		mp_uint32 patIndex = module->header.ord[orderIndex];
864 
865 		TXMPattern* pattern = &module->phead[patIndex];
866 
867 		mp_sint32 slotSize = pattern->effnum*2+2;
868 		mp_sint32 channum = pattern->channum, effnum = pattern->effnum;
869 
870 		mp_ubyte* srcSlot = pattern->patternData;
871 
872 		for (mp_sint32 rows = 0; rows < pattern->rows; rows++)
873 		{
874 			for (mp_sint32 c = 0;  c < channum; c++)
875 			{
876 				if (srcSlot[0])
877 					lastNote[c] = srcSlot[0];
878 
879 				if (srcSlot[1])
880 					lastIns[c] = srcSlot[1];
881 
882 				// ----------- store last operands for S3M/MDL/DBM effects ---------------
883 				const mp_ubyte* effSlot = srcSlot+2;
884 				for (mp_sint32 effCnt = 0; effCnt < effnum; effCnt++)
885 				{
886 					mp_ubyte effIn = *effSlot;
887 					mp_ubyte opIn = *(effSlot+1);
888 
889 					effSlot+=2;
890 
891 					if (effIn < 0x0f || effIn > 0x5a)
892 						continue;
893 
894 					switch (effIn)
895 					{
896 						case 0x0f:
897 							if (opIn >= 32)
898 								workBuffers.bpm = opIn;
899 							break;
900 						case 0x10:
901 							workBuffers.globalVolume = (mp_ubyte)(((mp_sint32)opIn*64)/255);
902 							break;
903 						case 0x16:
904 							if (opIn >= 32)
905 							{
906 								workBuffers.bpm = opIn;
907 							}
908 							else
909 							{
910 								if (opIn) lastTempoSlide[c] = opIn;
911 
912 								if (lastTempoSlide[c])
913 								{
914 									mp_ubyte y = lastTempoSlide[c]>>4;
915 									mp_ubyte x = lastTempoSlide[c]&0xf;
916 
917 									// tempo slide up
918 									if (y)
919 									{
920 										workBuffers.bpm+=x*(workBuffers.speed-1);
921 										if (workBuffers.bpm > 255)
922 											workBuffers.bpm = 255;
923 									}
924 									// tempo slide down
925 									else
926 									{
927 										workBuffers.bpm-=x*(workBuffers.speed-1);
928 										if (workBuffers.bpm < 32)
929 											workBuffers.bpm = 32;
930 									}
931 								}
932 							}
933 							break;
934 						case 0x1C:
935 							if (opIn)
936 								workBuffers.speed = opIn;
937 							break;
938 						case 0x20:
939 							if (!opIn) break;
940 							lastArpeggio[c] = opIn;
941 							break;
942 						case 0x43:
943 							if (!opIn) break;
944 							lastPorta[c] = opIn;
945 							break;
946 						case 0x44:
947 							if (!opIn) break;
948 							lastPorta[c] = opIn;
949 							break;
950 						case 0x45:
951 							if (!opIn) break;
952 							lastVolSlide[c] = opIn;
953 							break;
954 						case 0x46:
955 							if (!opIn) break;
956 							lastVolSlide[c] = opIn;
957 							break;
958 						case 0x47:
959 							if (!opIn) break;
960 							lastPorta[c] = opIn;
961 							break;
962 						case 0x48:
963 							if (!opIn) break;
964 							lastPorta[c] = opIn;
965 							break;
966 						case 0x49:
967 							if (!opIn) break;
968 							lastVolSlide[c] = opIn;
969 							break;
970 						case 0x52:
971 							workBuffers.baseBpm = opIn;
972 							break;
973 
974 						case 0x59:
975 						{
976 							if (opIn)
977 								lastGVolSlide[c] = opIn;
978 
979 							if (lastGVolSlide[c])
980 							{
981 								mp_ubyte y = lastGVolSlide[c]>>4;
982 								mp_ubyte x = lastGVolSlide[c]&0xf;
983 
984 								if (!(x == 0xF && y)&&!(y == 0xF && x))
985 								{
986 									if (x && y) x = 0;
987 
988 									if (y)
989 									{
990 										workBuffers.globalVolume+=y*(workBuffers.speed-1);
991 										if (workBuffers.globalVolume > 64)
992 											workBuffers.globalVolume = 64;
993 									}
994 									else if (x)
995 									{
996 										workBuffers.globalVolume-=x*(workBuffers.speed-1);
997 										if (workBuffers.globalVolume < 0)
998 											workBuffers.globalVolume = 0;
999 									}
1000 
1001 								}
1002 								else
1003 								{
1004 									// SUCKS
1005 									if (!(x==0x0F && !y) && !(y==0x0F && !x))
1006 									{
1007 										if (x==0x0F)
1008 										{
1009 											workBuffers.globalVolume += y;
1010 											if (workBuffers.globalVolume > 64)
1011 												workBuffers.globalVolume = 64;
1012 										}
1013 										else if (y==0x0F)
1014 										{
1015 											workBuffers.globalVolume -= x;
1016 											if (workBuffers.globalVolume < 0)
1017 												workBuffers.globalVolume = 0;
1018 										}
1019 									}
1020 								}
1021 							}
1022 							break;
1023 						}
1024 					}
1025 				}
1026 
1027 				srcSlot+=slotSize;
1028 
1029 			}
1030 		}
1031 	}
1032 }
1033 
convertPattern(const XModule * module,const TXMPattern * srcPattern,mp_ubyte * dstPattern,mp_sint32 numChannels,TWorkBuffers & workBuffers,bool verbose)1034 static mp_sint32 convertPattern(const XModule* module, const TXMPattern* srcPattern, mp_ubyte* dstPattern, mp_sint32 numChannels, TWorkBuffers& workBuffers, bool verbose)
1035 {
1036 
1037 	bool convertITTempoSlides = module ? (module->getType() == XModule::ModuleType_IT) : false;
1038 	bool newInsPTFlag = module ? ((module->header.flags & XModule::MODULE_PTNEWINSTRUMENT) != 0) : false;
1039 	bool newInsST3Flag = module ? ((module->header.flags & XModule::MODULE_ST3NEWINSTRUMENT) != 0) : false;
1040 
1041 	if (module)
1042 	{
1043 		mp_sint32 patNum = -1;
1044 		for (mp_uint32 i = 0; i < module->header.patnum; i++)
1045 		{
1046 			if (srcPattern == &module->phead[i])
1047 			{
1048 				patNum = i;
1049 				break;
1050 			}
1051 		}
1052 
1053 		if (patNum != -1)
1054 		{
1055 			mp_sint32 orderListPos = -1;
1056 			for (mp_uint32 i = 0; i < module->header.ordnum; i++)
1057 			{
1058 				if (module->header.ord[i] == patNum)
1059 				{
1060 					orderListPos = i;
1061 					break;
1062 				}
1063 			}
1064 
1065 			if (orderListPos != -1)
1066 			{
1067 				fillWorkBuffers(module, orderListPos, workBuffers);
1068 			}
1069 		}
1070 	}
1071 
1072 	mp_ubyte* lastNote = workBuffers.lastNote;
1073 	mp_ubyte* lastIns = workBuffers.lastIns;
1074 
1075 #ifdef MILKYTRACKER
1076 	newInsPTFlag = false;
1077 #endif
1078 
1079 	mp_ubyte* effectBuffer = new mp_ubyte[srcPattern->rows * numChannels * srcPattern->effnum];
1080 	mp_ubyte* swapBuffer = new mp_ubyte[srcPattern->rows * numChannels * srcPattern->effnum];
1081 	mp_sint32 numEffectsInBuffer = 0;
1082 
1083 	for (mp_sint32 rows = 0; rows < srcPattern->rows; rows++)
1084 	{
1085 		bool correctPLMFarJump				= false;
1086 		mp_uint32 correctPLMFarJumpChannel	= 0;
1087 		mp_sint32 PLMFarJumpPos				= 0;
1088 		mp_sint32 PLMFarJumpRow				= 0;
1089 
1090 		mp_sint32 c;
1091 
1092 		for (c = 0;  c < srcPattern->channum; c++)
1093 		{
1094 			if (c < numChannels)
1095 			{
1096 				mp_ubyte* dstSlot = dstPattern+(rows*(numChannels*5) + (c*5));
1097 				mp_ubyte* srcSlot = srcPattern->patternData+(rows*(srcPattern->channum*(srcPattern->effnum*2+2)) + c*(srcPattern->effnum*2+2));
1098 
1099 				if (srcSlot[0])
1100 					lastNote[c] = srcSlot[0];
1101 
1102 				if (srcSlot[1])
1103 				{
1104 					lastIns[c] = srcSlot[1];
1105 					//if (srcSlot[0])
1106 					//	lastIns2[c] = srcSlot[1];
1107 				}
1108 
1109 				mp_sint32 srcNote = (mp_sint32)srcSlot[0];
1110 
1111 				if (lastIns[c] && srcNote > 0 && srcNote <= XModule::NOTE_LAST)
1112 				{
1113 					srcNote+=workBuffers.noteRangeRemapper[lastIns[c]-1];
1114 					if (srcNote > XModule::NOTE_LAST || srcNote < 0)
1115 						srcNote = 0;
1116 				}
1117 				if (srcNote == XModule::NOTE_OFF || srcNote == XModule::NOTE_CUT) srcNote = 97;
1118 				else if (srcNote > 96) srcNote = 0;
1119 
1120 				dstSlot[0] = srcNote;
1121 
1122 				// instrument
1123 				dstSlot[1] = srcSlot[1];
1124 
1125 				convertEffects(srcSlot,
1126 							   srcPattern->effnum,
1127 							   dstSlot[2],
1128 							   dstSlot[3],
1129 							   dstSlot[4],
1130 							   c,
1131 							   workBuffers,
1132 							   effectBuffer,
1133 							   numEffectsInBuffer,
1134 							   swapBuffer,
1135 							   convertITTempoSlides);
1136 
1137 				// try to find workaround for PLM far-jump
1138 				if (module && module->getType() == XModule::ModuleType_PLM && dstSlot[3] == 0x0B)
1139 				{
1140 					mp_ubyte* eff = srcSlot+2;
1141 					for (mp_sint32 i = 0; i < srcPattern->effnum; i++)
1142 					{
1143 						if (eff[i*2] == 0x2B)
1144 						{
1145 							PLMFarJumpPos = eff[i*2+1];
1146 							PLMFarJumpRow = eff[((i+1)%srcPattern->effnum)*2+1];
1147 							correctPLMFarJump = true;
1148 							correctPLMFarJumpChannel = c;
1149 							break;
1150 						}
1151 					}
1152 				}
1153 
1154 				// * some nasty protracker style fixes
1155 				// * trying to emulate protracker 3.15 behaviour with FT2 methods
1156 				mp_sint32 i = srcSlot[1];
1157 				if (module && i && newInsPTFlag)
1158 				{
1159 					if (!dstSlot[0])
1160 					{
1161 						if (module->instr[i-1].samp == 0 ||
1162 							module->instr[i-1].snum[0] == -1)
1163 						{
1164 							dstSlot[0] = 97;
1165 						}
1166 						else
1167 						{
1168 							mp_sint32 s = module->instr[i-1].snum[0];
1169 							if (s != -1 && !dstSlot[2])
1170 								dstSlot[2] = (mp_ubyte)(((mp_sint32)module->smp[s].vol*64)/255)+0x10;
1171 						}
1172 					}
1173 					else
1174 					{
1175 						if (module->instr[i-1].samp == 0 ||
1176 							module->instr[i-1].snum[dstSlot[0]] == -1)
1177 						{
1178 							dstSlot[0] = 97;
1179 						}
1180 					}
1181 
1182 				}
1183 				else if (module && i && newInsST3Flag)
1184 				{
1185 					if (!dstSlot[0])
1186 					{
1187 						if (!(module->instr[i-1].samp == 0 ||
1188 							  module->instr[i-1].snum[0] == -1))
1189 						{
1190 							mp_sint32 s = module->instr[i-1].snum[0];
1191 							if (s != -1 && !dstSlot[2])
1192 								dstSlot[2] = (mp_ubyte)(((mp_sint32)module->smp[s].vol*64)/255)+0x10;
1193 						}
1194 						else
1195 						{
1196 							dstSlot[0] = 0;
1197 						}
1198 					}
1199 				}
1200 
1201 				// * trying to emulate MTM behaviour
1202 				// * Sample offset command triggers last note again
1203 				if (module && module->getType() == XModule::ModuleType_MTM && !dstSlot[0] && dstSlot[3] == 0x9)
1204 					dstSlot[0] = lastNote[c];
1205 
1206 			}
1207 
1208 			if (correctPLMFarJump)
1209 			{
1210 				for (c = 0;  c < srcPattern->channum; c++)
1211 				{
1212 					mp_ubyte* dstSlot = dstPattern+(rows*(numChannels*5) + (c*5));
1213 
1214 					if (dstSlot[3] == 0)
1215 					{
1216 						if (c > (signed)correctPLMFarJumpChannel)
1217 						{
1218 							dstSlot[3] = 0x0D;
1219 							dstSlot[4] = (PLMFarJumpRow/10)*16+(PLMFarJumpRow%10);
1220 						}
1221 						else
1222 						{
1223 							mp_ubyte* srcSlot = dstPattern+(rows*(numChannels*5) + (correctPLMFarJumpChannel*5));
1224 
1225 							dstSlot[3] = srcSlot[3];
1226 							dstSlot[4] = srcSlot[4];
1227 
1228 							srcSlot[3] = 0x0D;
1229 							srcSlot[4] = (PLMFarJumpRow/10)*16+(PLMFarJumpRow%10);
1230 						}
1231 						break;
1232 					}
1233 				}
1234 			}
1235 
1236 		}
1237 
1238 	}
1239 
1240 	delete[] swapBuffer;
1241 	delete[] effectBuffer;
1242 
1243 	return MP_OK;
1244 }
1245 
packPattern(const mp_ubyte * pattern,mp_ubyte * outputPattern,mp_sint32 numRows,mp_sint32 numChannels)1246 mp_sint32 packPattern(const mp_ubyte* pattern, mp_ubyte* outputPattern, mp_sint32 numRows, mp_sint32 numChannels)
1247 {
1248 	mp_sint32 i,j,z,b1,x,y;
1249 	mp_ubyte pack[6];
1250 
1251 	/*i = numRows*numChannels*5 - 1;
1252 	while (i > 0 && !pattern[i])
1253 		i--;
1254 	mp_sint32 max = i;
1255 
1256 	printf("%i, %i\n", numRows*numChannels*5, max);	*/
1257 
1258 	// -------------------------
1259 	// pack pattern (xm packing)
1260 	// -------------------------
1261 	j = z = b1 = 0;
1262 	for (x=0; x < numRows; x++)
1263 		for (y=0; y < numChannels; y++)
1264 		{
1265 			//if (z > max)
1266 			//	goto finishedPacking;
1267 
1268             memset(&pack,0,6);
1269             i=0;
1270             if (pattern[z])
1271 			{
1272 				b1=1;
1273 				pack[0]|=1;
1274 				pack[i+1]=pattern[z];
1275 				i++;
1276             }
1277             if (pattern[z+1])
1278 			{
1279 				b1=1;
1280 				pack[0]|=2;
1281 				pack[i+1]=pattern[z+1];
1282 				i++;
1283             }
1284             if (pattern[z+2])
1285 			{
1286 				b1=1;
1287 				pack[0]|=4;
1288 				pack[i+1]=pattern[z+2];
1289 				i++;
1290             }
1291             if (pattern[z+3])
1292 			{
1293 				b1=1;
1294 				pack[0]|=8;
1295 				pack[i+1]=pattern[z+3];
1296 				i++;
1297             }
1298             if (pattern[z+4])
1299 			{
1300 				b1=1;
1301 				pack[0]|=16;
1302 				pack[i+1]=pattern[z+4];
1303 				i++;
1304             }
1305             if (i<5)
1306 			{
1307 				pack[0]|=128;
1308 				memcpy(outputPattern+j,&pack,i+1);
1309 				j+=i+1;
1310             }
1311             else
1312 			{
1313 				memcpy(outputPattern+j,pattern+z,5);
1314 				j+=5;
1315             }
1316 
1317             z+=5;
1318 
1319 		}
1320 
1321 //finishedPacking:
1322 	return j;
1323 }
1324 
sort(mp_sword * array,mp_sint32 l,mp_sint32 r)1325 static void sort(mp_sword* array,mp_sint32 l, mp_sint32 r)
1326 {
1327 	mp_sint32 i,j;
1328 	mp_sword x,y;
1329 	i=l; j=r; x=array[(l+r)/2];
1330 	do
1331 	{
1332 		while (array[i]<x) i++;
1333 		while (x<array[j]) j--;
1334 		if (i<=j)
1335 		{
1336 			y=array[i]; array[i]=array[j]; array[j]=y;
1337 			i++; j--;
1338 		}
1339 	} while (i<=j);
1340 	if (l<j) sort(array,l,j);
1341 	if (i<r) sort(array,i,r);
1342 }
1343 
saveExtendedModule(const SYSCHAR * fileName)1344 mp_sint32 XModule::saveExtendedModule(const SYSCHAR* fileName)
1345 {
1346 	mp_sint32 i,j,k,l;
1347 
1348 	TWorkBuffers workBuffers;
1349 	workBuffers.bpm = header.speed;
1350 	workBuffers.speed = header.tempo;
1351 
1352 	// ------ prerequisites ---------------------------------
1353 
1354 	// step one, find last used pattern
1355 	mp_sint32 patNum = getNumUsedPatterns();
1356 	if (!patNum)
1357 		patNum++;
1358 
1359 	// step two, find last used instrument
1360 	mp_sint32 insNum = getNumUsedInstruments();
1361 	if (!insNum)
1362 		insNum++;
1363 
1364 	// ------ start ---------------------------------
1365 	XMFile f(fileName, true);
1366 
1367 	if (!f.isOpenForWriting())
1368 		return MP_DEVICE_ERROR;
1369 
1370 	f.write("Extended Module: ",1,17);
1371 
1372 	char titleBuffer[MP_MAXTEXT+1], titleBufferTemp[MP_MAXTEXT+1];
1373 	memset(titleBuffer, 0, sizeof(titleBuffer));
1374 	memset(titleBufferTemp, 0, sizeof(titleBufferTemp));
1375 	convertStr(reinterpret_cast<char*>(titleBuffer), reinterpret_cast<char*>(header.name), MP_MAXTEXT);
1376 	if (strlen(titleBuffer) > 20)
1377 	{
1378 		mp_sint32 i = 0;
1379 		mp_sint32 len = (mp_sint32)strlen(titleBuffer);
1380 		while (titleBuffer[i] <= ' ' && i < len)
1381 			i++;
1382 
1383 		memcpy(titleBufferTemp, titleBuffer+i, strlen(titleBuffer) - i);
1384 		f.write(titleBufferTemp, 1, 20);
1385 	}
1386 	else
1387 		f.write(header.name, 1, 20);
1388 	header.whythis1a = 0x1a;
1389 	f.writeByte(header.whythis1a);
1390 #ifdef MILKYTRACKER
1391 #include "../tracker/version.h"
1392 	f.write(MILKYTRACKER_VERSION_STRING, 1, 20);
1393 #else
1394 	f.write(header.tracker, 1, 20);
1395 #endif
1396 	header.ver = 0x104;
1397 	f.writeWord(header.ver);
1398 	header.hdrsize = 276;
1399 	f.writeDword(header.hdrsize);
1400 	f.writeWord(header.ordnum);
1401 	f.writeWord(header.restart);
1402 
1403 	mp_uword numChannels = header.channum&1 ? header.channum+1 : header.channum;
1404 
1405 	f.writeWord(numChannels);
1406 	f.writeWord(patNum);
1407 	f.writeWord(insNum);
1408 	f.writeWord(header.freqtab);
1409 	f.writeWord(header.tempo);
1410 	f.writeWord(header.speed);
1411 	f.write(header.ord,1,256);
1412 
1413 	mp_ubyte lowerNoteBound[256];
1414 	mp_ubyte upperNoteBound[256];
1415 
1416 	for (i = 0; i < 256; i++)
1417 	{
1418 		lowerNoteBound[i] = XModule::NOTE_LAST;
1419 		upperNoteBound[i] = 0;
1420 	}
1421 
1422 	mp_ubyte* lastIns = new mp_ubyte[header.channum];
1423 	memset(lastIns, 0, header.channum);
1424 
1425 	for (i = 0; i < patNum; i++)
1426 	{
1427 		TXMPattern* srcPattern = &phead[i];
1428 
1429 		mp_sint32 channum = srcPattern->channum >= header.channum ? header.channum : srcPattern->channum;
1430 
1431 		for (mp_sint32 rows = 0; rows < srcPattern->rows; rows++)
1432 			for (mp_sint32 c = 0;  c < channum; c++)
1433 			{
1434 
1435 				mp_ubyte* srcSlot = srcPattern->patternData+(rows*(srcPattern->channum*(srcPattern->effnum*2+2)) + c*(srcPattern->effnum*2+2));
1436 
1437 				if (srcSlot[1])
1438 					lastIns[c] = srcSlot[1];
1439 
1440 				if (lastIns[c] && srcSlot[0] && srcSlot[0] < XModule::NOTE_OFF)
1441 				{
1442 					if (srcSlot[0] > upperNoteBound[lastIns[c]-1]) upperNoteBound[lastIns[c]-1] = srcSlot[0];
1443 					if (srcSlot[0] < lowerNoteBound[lastIns[c]-1]) lowerNoteBound[lastIns[c]-1] = srcSlot[0];
1444 				}
1445 			}
1446 
1447 	}
1448 
1449 	delete[] lastIns;
1450 
1451 	for (i = 0; i < insNum; i++)
1452 	{
1453 		mp_sint32 remapper = 0;
1454 		if (upperNoteBound[i] > 96)
1455 			remapper = upperNoteBound[i] - 96;
1456 
1457 		if (remapper < lowerNoteBound[i])
1458 			workBuffers.noteRangeRemapper[i] = -remapper;
1459 
1460 #ifdef VERBOSE
1461 		printf("%i - %i (%i)\n", lowerNoteBound[i], upperNoteBound[i], workBuffers.noteRangeRemapper[i]);
1462 #endif
1463 	}
1464 
1465 	for (i = 0; i < patNum; i++)
1466 	{
1467 		mp_sint32 numRows = phead[i].rows;
1468 
1469 		if (numRows == 0)
1470 			numRows = 1;
1471 
1472 		mp_sint32 patChNum = (phead[i].channum+(phead[i].channum&1));
1473 
1474 		if (patChNum < numChannels)
1475 			patChNum = numChannels;
1476 
1477 		mp_sint32 len = numRows * patChNum * 5;
1478 
1479 		mp_ubyte* srcPattern = new mp_ubyte[len];
1480 		mp_ubyte* dstPattern = new mp_ubyte[len];
1481 
1482 		memset(srcPattern, 0, len);
1483 		memset(dstPattern, 0, len);
1484 
1485 		convertPattern(this, &phead[i], srcPattern, numChannels, workBuffers, false);
1486 
1487 		len = packPattern(srcPattern, dstPattern, numRows, numChannels);
1488 
1489 #ifdef VERBOSE
1490 		printf("Uncompressed pattern size: %i, compressed: %i\n", numRows * numChannels * 5, len);
1491 #endif
1492 
1493 		f.writeDword(9);
1494 		f.writeByte(0);
1495 		f.writeWord(numRows);
1496 		f.writeWord(len);
1497 
1498 		f.write(dstPattern, 1, len);
1499 
1500 		//printf("Packed Size: %i\n", len);
1501 
1502 		delete[] srcPattern;
1503 		delete[] dstPattern;
1504 	}
1505 
1506 	for (i = 0; i < insNum; i++)
1507 	{
1508 			//mp_sint32 maxSample = instr[i].samp - 1;
1509 			if (instr[i].samp > 0)
1510 			{
1511 				mp_sword usedSamples[256];
1512 				memset(usedSamples, 0, sizeof(usedSamples));
1513 				mp_sint32 numUsedSamples = 0;
1514 
1515 #ifdef MILKYTRACKER
1516 				if (type == ModuleType_XM && header.smpnum == header.insnum*16)
1517 				{
1518 					// save all samples within an instrument rather than the
1519 					// used ones (referenced by note mapping)
1520 					for (j = 0; j < 16; j++)
1521 						usedSamples[j] = i*16+j;
1522 
1523 					numUsedSamples = 0;
1524 
1525 					// find last used sample in instrument
1526 					for (j = 15; j >= 0; j--)
1527 					{
1528 						mp_sint32 index = usedSamples[j];
1529 						char buffer[MP_MAXTEXT+1];
1530 						convertStr(buffer, reinterpret_cast<char*>(smp[index].name), MP_MAXTEXT);
1531 						if (strlen(buffer) || smp[index].samplen)
1532 						{
1533 							numUsedSamples = j+1;
1534 							break;
1535 						}
1536 					}
1537 				}
1538 				else
1539 #endif
1540 				{
1541 					// find referenced samples in instrument and save those
1542 					for (j = 0; j < 96; j++)
1543 					{
1544 						mp_sword s = instr[i].snum[j];
1545 
1546 						if (s == -1)
1547 							continue;
1548 
1549 						bool used = false;
1550 						for (k = 0; k < numUsedSamples; k++)
1551 						{
1552 							if (usedSamples[k] == s)
1553 							{
1554 								used = true;
1555 								break;
1556 							}
1557 						}
1558 						if (!used && smp[s].sample && smp[s].samplen)
1559 							usedSamples[numUsedSamples++] = s;
1560 					}
1561 
1562 					sort(usedSamples, 0, numUsedSamples-1);
1563 				}
1564 
1565 				f.writeDword(numUsedSamples > 0 ? 263 : 29);
1566 				f.write(&instr[i].name,1,22);
1567 				f.writeByte(0);
1568 				f.writeWord(numUsedSamples);
1569 
1570 				if (!numUsedSamples)
1571 					continue;
1572 
1573 				f.writeDword(40);
1574 
1575 				mp_ubyte nbu[96];
1576 
1577 				for (j = 0; j < 96; j++)
1578 				{
1579 					mp_sword s = instr[i].snum[j];
1580 
1581 					for (k = 0; k < numUsedSamples; k++)
1582 						if (usedSamples[k] == s)
1583 						{
1584 							nbu[j] = k;
1585 							break;
1586 						}
1587 				}
1588 
1589 				f.write(nbu, 1, 96);
1590 
1591 				mp_sint32 venvIndex = -1;
1592 				mp_sint32 penvIndex = -1;
1593 
1594 				for (j = 0; j < numUsedSamples; j++)
1595 				{
1596 					if (smp[usedSamples[j]].venvnum && venvIndex == -1)
1597 						venvIndex = smp[usedSamples[j]].venvnum - 1;
1598 
1599 					if (smp[usedSamples[j]].penvnum && penvIndex == -1)
1600 						penvIndex = smp[usedSamples[j]].penvnum - 1;
1601 
1602 				}
1603 
1604 #ifdef VERBOSE
1605 				printf("%i, %i\n", venvIndex, penvIndex);
1606 #endif
1607 				mp_sint32 step = 0;
1608 
1609 				if (venvIndex >= 0 && venvIndex < header.volenvnum)
1610 				{
1611 					step = venvs[venvIndex].num > 12 ? venvs[venvIndex].num*256 / 12 : 256;
1612 					l = 0;
1613 					for (k = 0; k < 12; k++)
1614 					{
1615 						f.writeWord(venvs[venvIndex].env[l>>8][0]);
1616 						f.writeWord(venvs[venvIndex].env[l>>8][1]>>2);
1617 						l+=step;
1618 					}
1619 				}
1620 				else
1621 				{
1622 					// emptyness
1623 					for (k = 0; k < 12; k++)
1624 					{
1625 						f.writeWord(0);
1626 						f.writeWord(0);
1627 					}
1628 				}
1629 				if (penvIndex >= 0 && penvIndex < header.panenvnum)
1630 				{
1631 					step = penvs[penvIndex].num > 12 ? penvs[penvIndex].num*256 / 12 : 256;
1632 					l = 0;
1633 					for (k = 0; k < 12; k++)
1634 					{
1635 						f.writeWord(penvs[penvIndex].env[l>>8][0]);
1636 						f.writeWord(penvs[penvIndex].env[l>>8][1]>>2);
1637 						l+=step;
1638 					}
1639 				}
1640 				else
1641 				{
1642 					// emptyness
1643 					for (k = 0; k < 12; k++)
1644 					{
1645 						f.writeWord(0);
1646 						f.writeWord(0);
1647 					}
1648 				}
1649 
1650 				if (venvIndex >= 0 && venvIndex < header.volenvnum)
1651 					f.writeByte(venvs[venvIndex].num > 12 ? 12 : venvs[venvIndex].num);	// number of volume points
1652 				else
1653 					f.writeByte(0);	// number of volume points
1654 
1655 				if (penvIndex >= 0 && penvIndex < header.panenvnum)
1656 					f.writeByte(penvs[penvIndex].num > 12 ? 12 : penvs[penvIndex].num);	// number of panning points
1657 				else
1658 					f.writeByte(0);	// number of panning points
1659 
1660 				if (venvIndex >= 0 && venvIndex < header.volenvnum)
1661 				{
1662 					f.writeByte(venvs[venvIndex].sustain); // volume sustain point
1663 					f.writeByte(venvs[venvIndex].loops); // volume start point
1664 					f.writeByte(venvs[venvIndex].loope); // volume end point
1665 				}
1666 				else
1667 				{
1668 					f.writeByte(0);
1669 					f.writeByte(0);
1670 					f.writeByte(0);
1671 				}
1672 
1673 				if (penvIndex >= 0 && penvIndex < header.panenvnum)
1674 				{
1675 					f.writeByte(penvs[penvIndex].sustain); // panning sustain point
1676 					f.writeByte(penvs[penvIndex].loops); // panning start point
1677 					f.writeByte(penvs[penvIndex].loope); // panning end point
1678 				}
1679 				else
1680 				{
1681 					f.writeByte(0);
1682 					f.writeByte(0);
1683 					f.writeByte(0);
1684 				}
1685 
1686 				if (venvIndex >= 0 && venvIndex < header.volenvnum)
1687 					f.writeByte(venvs[venvIndex].type); // volume type
1688 				else
1689 					f.writeByte(0);
1690 
1691 				if (penvIndex >= 0 && penvIndex < header.panenvnum)
1692 					f.writeByte(penvs[penvIndex].type); // panning type
1693 				else
1694 					f.writeByte(0);
1695 
1696 				// take rest of the instrument info from first sample in the instrument
1697 				// will probably not work for exported .MDL songs.
1698 				// solution might be to create one instrument for each
1699 				// sample and remap instrument field in the patterns
1700 				l = usedSamples[0];
1701 
1702 				f.writeByte(smp[l].vibtype); // vibrato type
1703 				f.writeByte(smp[l].vibsweep); // vibrato sweep
1704 				f.writeByte(smp[l].vibdepth>>1); // vibrato depth
1705 				f.writeByte(smp[l].vibrate); // vibrato rate
1706 
1707 				if (instr[i].flags & TXMInstrument::IF_ITFADEOUT)
1708 					f.writeWord(instr[i].volfade>>1); // volume fadeout
1709 				else
1710 					f.writeWord(smp[l].volfade>>1); // volume fadeout
1711 
1712 				f.writeWord(0); // reserved
1713 
1714 				mp_ubyte extra[20];
1715 				memset(extra, 0, sizeof(extra));
1716 				f.write(extra, 1, 20);
1717 
1718 				for (j = 0; j < numUsedSamples; j++)
1719 				{
1720 					k = usedSamples[j];
1721 
1722 					f.writeDword((smp[k].type&16) ? smp[k].samplen <<1 : smp[k].samplen);
1723 					f.writeDword((smp[k].type&16) ? smp[k].loopstart << 1 : smp[k].loopstart);
1724 					f.writeDword((smp[k].type&16) ? smp[k].looplen << 1 : smp[k].looplen);
1725 
1726 					mp_sint32 relnote = smp[k].relnote - workBuffers.noteRangeRemapper[i] + header.relnote;
1727 					if (relnote<-96) relnote = -96;
1728 					if (relnote>95) relnote = 95;
1729 
1730 					mp_sint32 finetune = smp[k].finetune;
1731 
1732 					// make some ULT linear finetune to finetune & relative note num approximation
1733 					if (smp[k].freqadjust != 0)
1734 					{
1735 						mp_sint32 c4spd = getc4spd(relnote,finetune);
1736 						c4spd+=((c4spd*smp[k].freqadjust)/32768);
1737 
1738 						mp_sbyte rn,ft;
1739 						convertc4spd(c4spd, &ft, &rn);
1740 						finetune = ft;
1741 						relnote = rn;
1742 					}
1743 
1744 					f.writeByte(smp[k].vol*64/255);
1745 					f.writeByte((mp_sbyte)finetune);
1746 
1747 					mp_ubyte type = smp[k].type;
1748 					// Only alowed bits 0,1 and 3
1749 					type &= 3+16;
1750 					// Bits 0 and 1 are not allowed to be set at the same time
1751 					if ((type & 3) == 3) type &= ~1;
1752 
1753 					f.writeByte(type);
1754 					f.writeByte((smp[k].flags & 2) ? smp[k].pan : 0x80);
1755 
1756 					f.writeByte((mp_sbyte)relnote);
1757 					f.writeByte(0);
1758 
1759 					f.write(smp[k].name, 1, 22);
1760 				}
1761 
1762 				for (j = 0; j < numUsedSamples; j++)
1763 				{
1764 					k = usedSamples[j];
1765 
1766 					if (!smp[k].sample)
1767 						continue;
1768 
1769 					if (smp[k].type & 16)
1770 					{
1771 						mp_sword* packedSampleData = new mp_sword[smp[k].samplen];
1772 
1773 						mp_sword b1,b2,b3;
1774 
1775 						b1=0;
1776 						for (mp_uint32 j = 0; j < smp[k].samplen; j++)
1777 						{
1778 							b3 = smp[k].getSampleValue(j);
1779 							b2 = b3-b1;
1780 							packedSampleData[j] = b2;
1781 							b1 = b3;
1782 						}
1783 
1784 						f.writeWords((mp_uword*)packedSampleData, smp[k].samplen);
1785 
1786 						delete[] packedSampleData;
1787 
1788 					}
1789 					else
1790 					{
1791 						mp_sbyte* packedSampleData = new mp_sbyte[smp[k].samplen];
1792 
1793 						mp_sbyte b1,b2,b3;
1794 
1795 						b1=0;
1796 						for (mp_uint32 j = 0; j < smp[k].samplen; j++)
1797 						{
1798 							b3 = smp[k].getSampleValue(j);
1799 							b2 = b3-b1;
1800 							packedSampleData[j] = b2;
1801 							b1 = b3;
1802 						}
1803 
1804 						f.write(packedSampleData, 1, smp[k].samplen);
1805 
1806 						delete[] packedSampleData;
1807 					}
1808 				}
1809 			}
1810 			else
1811 			{
1812 				f.writeDword(instr[i].samp > 0 ? 263 : 29);
1813 				f.write(&instr[i].name,1,22);
1814 				f.writeByte(0);
1815 				f.writeWord(instr[i].samp);
1816 			}
1817 
1818 	}
1819 
1820 
1821 	return MP_OK;
1822 }
1823 
swap(mp_uword x)1824 static mp_uword swap(mp_uword x)
1825 {
1826 	return (x>>8)+((x&255)<<8);
1827 }
1828 
prep(mp_sint32 v)1829 static mp_uword prep(mp_sint32 v)
1830 {
1831 	const int MAXSIZE = 0x1ffff;
1832 	if (v&1) v++;
1833 	if (v > MAXSIZE)
1834 		v = MAXSIZE;
1835 
1836 	return (mp_uword)(v >> 1);
1837 }
1838 
saveProtrackerModule(const SYSCHAR * fileName)1839 mp_sint32 XModule::saveProtrackerModule(const SYSCHAR* fileName)
1840 {
1841 	static const mp_sint32 periods[12] = {1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907};
1842 
1843 	static const mp_sint32 originalPeriods[] = {1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906,
1844 												856,808,762,720,678,640,604,570,538,508,480,453,
1845 											    428,404,381,360,339,320,302,285,269,254,240,226,
1846 												214,202,190,180,170,160,151,143,135,127,120,113,
1847 												107,101,95,90,85,80,75,71,67,63,60,56};
1848 
1849 	TWorkBuffers workBuffers;
1850 
1851 	XMFile f(fileName, true);
1852 
1853 	if (!f.isOpenForWriting())
1854 		return MP_DEVICE_ERROR;
1855 
1856 	f.write(header.name,1,20);
1857 
1858 	mp_sint32 i,j,k;
1859 
1860 // - instruments -------------------------------------------
1861 	for (i = 0; i < 31; i++)
1862 	{
1863 		f.write(instr[i].name, 1, 22);
1864 
1865 		// sample seems to be used
1866 		if (instr[i].samp)
1867 		{
1868 			mp_sint32 s = -1;
1869 			for (j = 0; j < 120; j++)
1870 				if (instr[i].snum[j] >= 0)
1871 				{
1872 					s = instr[i].snum[j];
1873 					break;
1874 				}
1875 
1876 			if (s == -1)
1877 				goto unused;
1878 
1879 			mp_sint32 fti = (mp_sint32)smp[s].finetune + 128;
1880 			if (!(fti & 0xF) && !smp[s].relnote)
1881 			{
1882 				k = (((mp_uint32)(fti-128)) >> 4) & 0xF;
1883 			}
1884 			else
1885 			{
1886 				mp_sint32 c4spd = getc4spd(smp[s].relnote, smp[s].finetune);
1887 
1888 				mp_sint32 dc4 = abs(sfinetunes[0]-c4spd);
1889 
1890 				k = 0;
1891 				for (j = 1; j < 16; j++)
1892 					if (abs(sfinetunes[j]-c4spd) < dc4)
1893 					{
1894 						dc4 = abs(sfinetunes[j]-c4spd);
1895 						k = j;
1896 					}
1897 			}
1898 
1899 			f.writeWord(swap(prep(smp[s].samplen)));
1900 
1901 			f.writeByte(k);
1902 			f.writeByte((mp_ubyte)(((mp_sint32)smp[s].vol*64)/255));
1903 
1904 			if (smp[s].type & 3)
1905 			{
1906 				mp_sint32 loopend = /*smp[s].loopstart + */smp[s].looplen;
1907 
1908 				if (smp[s].type & 32)
1909 				{
1910 					f.writeWord(0);
1911 				}
1912 				else
1913 				{
1914 					if (!smp[s].loopstart && smp[s].looplen != smp[s].samplen)
1915 					{
1916 						f.writeWord(swap(1));
1917 					}
1918 					else if (!smp[s].loopstart && smp[s].looplen == smp[s].samplen)
1919 					{
1920 						f.writeWord(0);
1921 					}
1922 					else
1923 						f.writeWord(swap(prep(smp[s].loopstart)));
1924 				}
1925 
1926 				f.writeWord(swap(prep(loopend)));
1927 			}
1928 			else
1929 			{
1930 				f.writeWord(swap(0));
1931 				f.writeWord(swap(1));
1932 			}
1933 
1934 		}
1935 		else
1936 		{
1937 unused:
1938 			f.writeWord(swap(0));
1939 			f.writeByte(0);
1940 			f.writeByte(0);
1941 			f.writeWord(swap(0));
1942 			f.writeWord(swap(1));
1943 		}
1944 
1945 	}
1946 
1947 // - orderlist -------------------------------------------
1948 	f.writeByte((mp_ubyte)header.ordnum);
1949 
1950 	f.writeByte(127);
1951 
1952 	mp_ubyte ord[128];
1953 
1954 	memset(ord, 0, sizeof(ord));
1955 
1956 	j = 0;
1957 	for (i = 0; i < 128; i++)
1958 	{
1959 		if (header.ord[i] < 254)
1960 			ord[j++] = header.ord[i];
1961 		else if (header.ord[i] == 255)
1962 			break;
1963 	}
1964 
1965 	f.write(ord, 1, 128);
1966 
1967 	mp_uword numChannels = header.channum&1 ? header.channum+1 : header.channum;
1968 
1969 	if (numChannels < 1 || numChannels > 99)
1970 		return MP_UNSUPPORTED;
1971 
1972 // - patterns -------------------------------------------
1973 	mp_sint32 numPatterns = 0;
1974 	for (i = 0; i < 128; i++)
1975 	{
1976 		if (ord[i] > numPatterns)
1977 			numPatterns = ord[i];
1978 	}
1979 
1980 	char modMagic[4];
1981 	if(numChannels == 4)
1982 	{
1983 		// ProTracker may not load files with more than 64 patterns correctly if we do not specify the M!K! magic.
1984 		if(numPatterns <= 63)
1985 			memcpy(modMagic, "M.K.", 4);
1986 		else
1987 			memcpy(modMagic, "M!K!", 4);
1988 	} else if(numChannels < 10)
1989 	{
1990 		memcpy(modMagic, "0CHN", 4);
1991 		modMagic[0] += static_cast<char>(numChannels);
1992 	} else
1993 	{
1994 		memcpy(modMagic, "00CH", 4);
1995 		modMagic[0] += static_cast<char>(numChannels / 10u);
1996 		modMagic[1] += static_cast<char>(numChannels % 10u);
1997 	}
1998 	f.write(modMagic, 1, 4);
1999 
2000 	for (i = 0; i < numPatterns+1; i++)
2001 	{
2002 		mp_sint32 numRows = phead[i].rows;
2003 
2004 		if (numRows == 0)
2005 			numRows = 1;
2006 
2007 		mp_sint32 patChNum = (phead[i].channum+(phead[i].channum&1));
2008 
2009 		if (patChNum < numChannels)
2010 			patChNum = numChannels;
2011 
2012 		mp_sint32 len = numRows * patChNum * 5;
2013 		mp_sint32 lenDst = (numRows < 64 ? 64 : numRows) * patChNum * 4;
2014 
2015 		mp_ubyte* srcPattern = new mp_ubyte[len];
2016 		mp_ubyte* dstPattern = new mp_ubyte[lenDst];
2017 
2018 		memset(srcPattern, 0, len);
2019 		memset(dstPattern, 0, lenDst);
2020 
2021 		convertPattern(this, &phead[i], srcPattern, numChannels, workBuffers, false);
2022 
2023 		for (mp_sint32 r = 0; r < 64; r++)
2024 			for (mp_sint32 c = 0; c < numChannels; c++)
2025 			{
2026 
2027 				if (r < numRows)
2028 				{
2029 
2030 					mp_sint32 srcIndex = (r*numChannels*5)+(c*5);
2031 					mp_sint32 dstIndex = (r*numChannels*4)+(c*4);
2032 
2033 					mp_sint32 period = 0;
2034 
2035 					mp_ubyte note = srcPattern[srcIndex];
2036 
2037 					//note = r+24+1;
2038 
2039 					if (note)
2040 					{
2041 						note--;
2042 						if (note >= 24 && note < 24+12*5)
2043 							period = originalPeriods[note-24];
2044 						else
2045 							period = (periods[note%12]*16>>((note/12)))>>2;
2046 					}
2047 
2048 					mp_ubyte ins = srcPattern[srcIndex+1];
2049 
2050 					if (ins > 31)
2051 						ins = 0;
2052 
2053 					mp_ubyte eff = 0;
2054 					mp_ubyte op = 0;
2055 
2056 					// First convert volume command to PT compatible effect again :)
2057 					XModule::convertXMVolumeEffects(srcPattern[srcIndex+2], eff, op);
2058 					mp_ubyte tmpEff = eff, tmpOp = op;
2059 					convertEffect(tmpEff, tmpOp, eff, op, c, workBuffers, getType() == XModule::ModuleType_IT);
2060 
2061 					// Having an effect? Overwrite what we already have...
2062 					if (srcPattern[srcIndex+3] || srcPattern[srcIndex+4])
2063 					{
2064 						eff = srcPattern[srcIndex+3];
2065 						op = srcPattern[srcIndex+4];
2066 					}
2067 
2068 					if (eff > 0x0f)
2069 					{
2070 						eff = op = 0;
2071 					}
2072 
2073 					/*if (srcPattern[srcIndex+2] >= 0x10 && srcPattern[srcIndex+2] <= 0x50 &&
2074 						eff == 0 && op == 0)
2075 					{
2076 						eff = 0x0C;
2077 						op = srcPattern[srcIndex+2] - 0x10;
2078 					}*/
2079 
2080 					dstPattern[dstIndex] = (ins & 0xF0) + ((period>>8)&0x0F);
2081 					dstPattern[dstIndex+1] = (mp_ubyte)(period&0xFF);
2082 					dstPattern[dstIndex+2] = ((ins & 0x0F) << 4) + (eff);
2083 					dstPattern[dstIndex+3] = op;
2084 
2085 				}
2086 
2087 			}
2088 
2089 		f.write(dstPattern, 4, numChannels*64);
2090 
2091 		delete[] srcPattern;
2092 		delete[] dstPattern;
2093 	}
2094 
2095 	for (i = 0; i < header.smpnum; i++)
2096 	{
2097 		mp_uint32 smplen = prep(smp[i].samplen) << 1;
2098 		mp_uint32 j = 0;
2099 
2100 		// Ensure first 2 bytes are zero in non-looping
2101 		// samples (for Protracker/Amiga compatibility)
2102 		if(!(smp[i].type & 0xef) && smplen >= 2)
2103 		{
2104 			f.writeWord(0);
2105 			j = 2;;
2106 		}
2107 
2108 		if (smp[i].type & 16)
2109 		{
2110 			for (; j < smplen; j++)
2111 				f.writeByte(smp[i].getSampleValue(j) >> 8);
2112 		}
2113 		else
2114 		{
2115 			for (; j < smplen; j++)
2116 				f.writeByte(smp[i].getSampleValue(j));
2117 		}
2118 	}
2119 
2120 	return MP_OK;
2121 }
2122 
2123 #ifdef MILKYTRACKER
saveExtendedPattern(const SYSCHAR * fileName) const2124 bool TXMPattern::saveExtendedPattern(const SYSCHAR* fileName) const
2125 {
2126 	// Note: For FT2 compatibility, .XP files are fixed at 32 channels.
2127 	// TODO:  Create a version 2 format for variable channel counts
2128 	TWorkBuffers workBuffers;
2129 
2130 	// ------ start ---------------------------------
2131 	XMFile f(fileName, true);
2132 
2133 	if (!f.isOpenForWriting())
2134 		return false;
2135 
2136 	f.writeWord(0x1);
2137 	f.writeWord(rows);
2138 
2139 	mp_sint32 len = rows * 32 * 5;
2140 
2141 	mp_ubyte* srcPattern = new mp_ubyte[len];
2142 
2143 	memset(srcPattern, 0, len);
2144 
2145 	convertPattern(NULL, this, srcPattern, 32, workBuffers, false);
2146 
2147 	f.write(srcPattern, 1, len);
2148 
2149 	delete[] srcPattern;
2150 
2151 	return true;
2152 }
2153 
saveExtendedTrack(const SYSCHAR * fileName,mp_uint32 channel) const2154 bool TXMPattern::saveExtendedTrack(const SYSCHAR* fileName, mp_uint32 channel) const
2155 {
2156 	if (channel >= channum)
2157 		return false;
2158 
2159 	TWorkBuffers workBuffers;
2160 
2161 	// ------ start ---------------------------------
2162 	XMFile f(fileName, true);
2163 
2164 	if (!f.isOpenForWriting())
2165 		return false;
2166 
2167 	f.writeWord(0x1);
2168 	f.writeWord(rows);
2169 
2170 	mp_sint32 len = rows * 5;
2171 
2172 	mp_ubyte* srcPattern = new mp_ubyte[rows * channum * 5];
2173 	mp_ubyte* dstPattern = new mp_ubyte[len];
2174 
2175 	convertPattern(NULL, this, srcPattern, channum, workBuffers, false);
2176 
2177 	for (mp_sint32 r = 0; r < rows; r++)
2178 	{
2179 		mp_sint32 srcIndex = r*this->channum*5 + channel*5;
2180 		dstPattern[r*5] = srcPattern[srcIndex];
2181 		dstPattern[r*5+1] = srcPattern[srcIndex+1];
2182 		dstPattern[r*5+2] = srcPattern[srcIndex+2];
2183 		dstPattern[r*5+3] = srcPattern[srcIndex+3];
2184 		dstPattern[r*5+4] = srcPattern[srcIndex+4];
2185 	}
2186 
2187 	f.write(dstPattern, 1, len);
2188 
2189 	delete[] srcPattern;
2190 	delete[] dstPattern;
2191 
2192 	return true;
2193 }
2194 
loadExtendedPattern(const SYSCHAR * fileName)2195 bool TXMPattern::loadExtendedPattern(const SYSCHAR* fileName)
2196 {
2197 	XMFile f(fileName);
2198 
2199 	if (f.readWord() != 0x01)
2200 		return false;
2201 
2202 	mp_uword rows = f.readWord();
2203 
2204 	if (rows == 0 || rows > 256)
2205 		return false;
2206 
2207 	mp_sint32 len = rows * 32 * 5;
2208 
2209 	mp_ubyte* srcPattern = new mp_ubyte[len];
2210 
2211 	f.read(srcPattern, 1, len);
2212 
2213 	// throw away old pattern
2214 	delete[] patternData;
2215 	this->rows = rows;
2216 	this->channum = 32;
2217 	this->effnum = 2;
2218 
2219 	patternData = new mp_ubyte[rows*channum*(effnum*2+2)];
2220 
2221 	mp_ubyte* slot = srcPattern;
2222 
2223 	mp_sint32 bc = 0;
2224 	for (mp_sint32 r=0;r<rows;r++) {
2225 		for (mp_sint32 c=0;c<channum;c++) {
2226 
2227 			char gl=0;
2228 			for (mp_sint32 i=0;i<XModule::numValidXMEffects;i++)
2229 				if (slot[3]==XModule::validXMEffects[i]) gl=1;
2230 
2231 			if (!gl) slot[3]=slot[4]=0;
2232 
2233 			if ((slot[3]==0xC)||(slot[3]==0x10)) {
2234 				slot[4] = XModule::vol64to255(slot[4]);
2235 			}
2236 
2237 			if ((!slot[3])&&(slot[4])) slot[3]=0x20;
2238 
2239 			if (slot[3]==0xE) {
2240 				slot[3]=(slot[4]>>4)+0x30;
2241 				slot[4]=slot[4]&0xf;
2242 			}
2243 
2244 			if (slot[3]==0x21) {
2245 				slot[3]=(slot[4]>>4)+0x40;
2246 				slot[4]=slot[4]&0xf;
2247 			}
2248 
2249 			if (slot[0]==97) slot[0]=XModule::NOTE_OFF;
2250 
2251 			patternData[bc]=slot[0];
2252 			patternData[bc+1]=slot[1];
2253 
2254 			XModule::convertXMVolumeEffects(slot[2], patternData[bc+2], patternData[bc+3]);
2255 
2256 			patternData[bc+4]=slot[3];
2257 			patternData[bc+5]=slot[4];
2258 
2259 			bc+=6;
2260 			slot+=5;
2261 		} // for c
2262 
2263 	} // for r
2264 
2265 
2266 	delete[] srcPattern;
2267 
2268 	return true;
2269 }
2270 
loadExtendedTrack(const SYSCHAR * fileName,mp_uint32 channel)2271 bool TXMPattern::loadExtendedTrack(const SYSCHAR* fileName, mp_uint32 channel)
2272 {
2273 	XMFile f(fileName);
2274 
2275 	if (f.readWord() != 0x01)
2276 		return false;
2277 
2278 	mp_uword rows = f.readWord();
2279 
2280 	if (rows == 0 || rows > 256)
2281 		return false;
2282 
2283 	if (rows > this->rows)
2284 		rows = this->rows;
2285 
2286 	mp_sint32 len = rows * 32 * 5;
2287 
2288 	mp_ubyte* srcPattern = new mp_ubyte[len];
2289 
2290 	f.read(srcPattern, 1, len);
2291 
2292 	// throw away old pattern
2293 	mp_ubyte* slot = srcPattern;
2294 
2295 	mp_sint32 bc = 0, r;
2296 	for (r=0;r<rows;r++)
2297 	{
2298 		bc = r*this->channum*(this->effnum*2+2) + channel*(this->effnum*2+2);
2299 
2300 		char gl=0;
2301 		for (mp_sint32 i=0;i<XModule::numValidXMEffects;i++)
2302 			if (slot[3]==XModule::validXMEffects[i]) gl=1;
2303 
2304 		if (!gl) slot[3]=slot[4]=0;
2305 
2306 		if ((slot[3]==0xC)||(slot[3]==0x10)) {
2307 			slot[4] = XModule::vol64to255(slot[4]);
2308 		}
2309 
2310 		if ((!slot[3])&&(slot[4])) slot[3]=0x20;
2311 
2312 		if (slot[3]==0xE) {
2313 			slot[3]=(slot[4]>>4)+0x30;
2314 			slot[4]=slot[4]&0xf;
2315 		}
2316 
2317 		if (slot[3]==0x21) {
2318 			slot[3]=(slot[4]>>4)+0x40;
2319 			slot[4]=slot[4]&0xf;
2320 		}
2321 
2322 		if (slot[0]==97) slot[0]=XModule::NOTE_OFF;
2323 
2324 		patternData[bc]=slot[0];
2325 		patternData[bc+1]=slot[1];
2326 
2327 		XModule::convertXMVolumeEffects(slot[2], patternData[bc+2], patternData[bc+3]);
2328 
2329 		patternData[bc+4]=slot[3];
2330 		patternData[bc+5]=slot[4];
2331 
2332 		slot+=5;
2333 	} // for r
2334 
2335 	for (r = rows; r < this->rows; r++)
2336 	{
2337 		bc = r*this->channum*(this->effnum*2+2) + channel*(this->effnum*2+2);
2338 		memset(patternData + bc, 0, (this->effnum*2+2));
2339 	}
2340 
2341 	delete[] srcPattern;
2342 
2343 	return true;
2344 }
2345 
2346 #endif
2347 
getNumUsedPatterns()2348 mp_sint32 XModule::getNumUsedPatterns()
2349 {
2350 	mp_sint32 i;
2351 
2352 	mp_sint32 patNum = header.patnum;
2353 	for (i = header.patnum - 1; i > 0; i--)
2354 	{
2355 		TXMPattern* pattern = &phead[i];
2356 
2357 		if (pattern->patternData == NULL)
2358 			continue;
2359 
2360 		mp_sint32 slotSize = pattern->effnum * 2 + 2;
2361 
2362 		mp_sint32 patternSize = slotSize * pattern->channum * pattern->rows;
2363 
2364 		bool empty = true;
2365 		for (mp_sint32 j = 0; j < patternSize; j++)
2366 			if (pattern->patternData[j])
2367 			{
2368 				empty = false;
2369 				patNum = i+1;
2370 				break;
2371 			}
2372 
2373 		if (empty)
2374 		{
2375 			bool found = false;
2376 			for (mp_sint32 j = 0; j < header.ordnum; j++)
2377 				if (header.ord[j] == i)
2378 				{
2379 					found = true;
2380 					break;
2381 				}
2382 
2383 			if (found)
2384 			{
2385 				patNum = i+1;
2386 				break;
2387 			}
2388 		}
2389 		else
2390 		{
2391 			patNum = i+1;
2392 			break;
2393 		}
2394 	}
2395 
2396 	if (i == 0)
2397 		return 0;
2398 
2399 	return patNum;
2400 }
2401 
getNumUsedInstruments()2402 mp_sint32 XModule::getNumUsedInstruments()
2403 {
2404 	mp_sint32 i;
2405 
2406 	mp_sint32 insNum = header.insnum;
2407 	for (i = header.insnum - 1; i > 0; i--)
2408 	{
2409 		mp_ubyte buffer[MP_MAXTEXT+1];
2410 
2411 		convertStr(reinterpret_cast<char*>(buffer), reinterpret_cast<char*>(instr[i].name), MP_MAXTEXT, false);
2412 
2413 		if (strlen((char*)buffer))
2414 		{
2415 			insNum = i+1;
2416 			break;
2417 		}
2418 
2419 		if (instr[i].samp)
2420 		{
2421 
2422 			for (mp_sint32 j = 0; j < 120; j++)
2423 			{
2424 				mp_sint32 s = instr[i].snum[j];
2425 				if (s >= 0)
2426 				{
2427 					convertStr(reinterpret_cast<char*>(buffer), reinterpret_cast<char*>(smp[s].name), MP_MAXTEXT, false);
2428 					if (strlen((char*)buffer) || (smp[s].sample && smp[s].samplen))
2429 					{
2430 						insNum = i+1;
2431 						goto insFound;
2432 					}
2433 				}
2434 			}
2435 		}
2436 	}
2437 
2438 insFound:
2439 	if (i == 0)
2440 		return 0;
2441 
2442 	return insNum;
2443 }
2444