1 /* OpenCP Module Player
2 * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3 *
4 * XMPlay - Module player for XM/MOD and affiliate formats
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * revision history: (please note changes here)
21 * -nb980510 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
22 * -first release
23 * -kb980717 Tammo Hinrichs <opencp@gmx.net>
24 * -removed all references to gmd structures to make this more flexible
25 * -MOD: added module flag "ismod" to handle some protracker "features"
26 * (YEZ! Finally this player is chiptune capable!)
27 * -fixed envelope handling (sustain point was ignored when loopstart,
28 * loopend and sustain point were the same)
29 * -added plenty of effect status variables for screen output
30 * -fixed "always loop the last pattern" bug
31 * -MOD: fixed "offset greater than samplelength" bug
32 * -MOD: rewrote PlayNote() to achieve perfect PQE
33 * (Protracker Quirk Emulation ;)
34 * -MOD: enabled tick0 effects while pattern delay
35 * -MOD: added second "set speed" command for vblank timed modules
36 * -added "set finetune" command (E5x) (thanks to jt_letgo.xm ;)
37 * -added panpos array to xmodule for MOD/MXM channel panning
38 * -made vibratos weaker (yes, i didnt recognize that sooner, just
39 * blame me)
40 * -fixed playnote() again a bit
41 * -kb981210 Tammo Hinrichs <opencp@gmx.net>
42 * -set max channels to 256 to play modplug 64chn XMs and such
43 * -again many fixes in playnote() ( when... WHEN... )
44 * -kb990401 Tammo Hinrichs <opencp@gmx.net>
45 * -Note Retrig fixed
46 * -ryg990426 Fabian Giesen <fabian@jdcs.su.nw.schule.de>
47 * -^^^ put this fix into cvs because kb was too lazy and i was stupid
48 * enuff to say i would do the job :)
49 * -doj20020901 Dirk Jagdmann <doj@cubic.org>
50 * -enable/disable pattern looping
51 */
52
53 #include "config.h"
54 #include <string.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include "types.h"
58 #include "cpiface/cpiface.h"
59 #include "dev/mcp.h"
60 #include "xmplay.h"
61 #include "stuff/err.h"
62
63 struct channel
64 {
65 int chVol;
66 int chFinalVol;
67 int chPan;
68 int chFinalPan;
69 int32_t chPitch;
70 int32_t chFinalPitch;
71 int curnote;
72
73 uint8_t chCurIns;
74 uint8_t chLastIns;
75 int chCurNormNote;
76 uint8_t chSustain;
77 uint16_t chFadeVol;
78 uint16_t chAVibPos;
79 uint32_t chAVibSwpPos;
80 uint32_t chVolEnvPos;
81 uint32_t chPanEnvPos;
82
83 uint8_t chDefVol;
84 int chDefPan;
85 uint8_t chCommand;
86 uint8_t chVCommand;
87 int32_t chPortaToPitch;
88 int32_t chPortaToVal;
89 uint8_t chVolSlideVal;
90 uint8_t chGVolSlideVal;
91 uint8_t chVVolPanSlideVal;
92 uint8_t chPanSlideVal;
93 uint8_t chFineVolSlideUVal;
94 uint8_t chFineVolSlideDVal;
95 int32_t chPortaUVal;
96 int32_t chPortaDVal;
97 uint8_t chFinePortaUVal;
98 uint8_t chFinePortaDVal;
99 uint8_t chXFinePortaUVal;
100 uint8_t chXFinePortaDVal;
101 uint8_t chVibRate;
102 uint8_t chVibPos;
103 uint8_t chVibType;
104 uint8_t chVibDep;
105 uint8_t chTremRate;
106 uint8_t chTremPos;
107 uint8_t chTremType;
108 uint8_t chTremDep;
109 uint8_t chPatLoopCount;
110 uint8_t chPatLoopStart;
111 uint8_t chArpPos;
112 uint8_t chArpNotes[3];
113 uint8_t chActionTick;
114 uint8_t chMRetrigPos;
115 uint8_t chMRetrigLen;
116 uint8_t chMRetrigAct;
117 uint8_t chDelayNote;
118 uint8_t chDelayIns;
119 uint8_t chDelayVol;
120 uint8_t chOffset;
121 uint8_t chGlissando;
122 uint8_t chTremorPos;
123 uint8_t chTremorLen;
124 uint8_t chTremorOff;
125 uint8_t chSync;
126 int chSyncTime;
127 int delayfreq;
128
129 unsigned int nextstop;
130 unsigned int nextsamp;
131 unsigned int nextpos;
132 struct xmpsample *cursamp;
133
134 int evpos0;
135 int evmodtype;
136 int evmod;
137 int evmodpos;
138 int evpos;
139 int evtime;
140
141 int notehit;
142 uint8_t volslide;
143 uint8_t pitchslide;
144 uint8_t panslide;
145 uint8_t volfx;
146 uint8_t pitchfx;
147 uint8_t notefx;
148 uint8_t fx;
149 };
150
151 static int looping;
152 static int looped;
153 static int usersetpos;
154 static struct channel channels[256];
155
156 static uint8_t mutech[256];
157 static uint8_t globalvol;
158 static uint8_t globalfx;
159
160 static uint8_t curtick;
161 static uint8_t curtempo;
162 static uint8_t tick0;
163
164 static int currow;
165 static uint8_t (*patptr)[5];
166 static int patlen;
167 static int curord;
168
169 static int nord;
170 static int ninst;
171 static int nsamp;
172 static int linearfreq;
173 static int nchan;
174 static int loopord;
175 static int nenv;
176 static char ismod;
177 static char ft2_e60bug;
178 static struct xmpinstrument *instruments;
179 static struct xmpsample *samples;
180 static struct sampleinfo *sampleinfos;
181 static struct xmpenvelope *envelopes;
182 static uint8_t (**patterns)[5];
183 static uint16_t *orders;
184 static uint16_t *patlens;
185
186 static int jumptoord;
187 static int jumptorow;
188 static int nextpatternrow; /* which row to go do, when doing roll-over at the end of pattern - normally row 0, except for Fast Tracker II E60 bug */
189 static int patdelay;
190
191 static uint8_t procnot;
192 static uint8_t procins;
193 static uint8_t procvol;
194 static uint8_t proccmd;
195 static uint8_t procdat;
196 static int firstspeed;
197 static int curbpm;
198
199 static int realsync;
200 static int realsynctime;
201
202 static int realpos;
203
204 static int (*que)[4];
205 static int querpos;
206 static int quewpos;
207 static int quelen;
208 static int cmdtime;
209 static int realtempo;
210 static int realspeed;
211 static int realgvol;
212
213
214 enum
215 {
216 quePos, queSync, queTempo, queSpeed, queGVol
217 };
218
219 static short sintab[256]=
220 {
221 0, 50, 100, 151, 201, 251, 301, 350,
222 400, 449, 498, 546, 595, 642, 690, 737,
223 784, 830, 876, 921, 965, 1009, 1053, 1096,
224 1138, 1179, 1220, 1260, 1299, 1338, 1375, 1412,
225 1448, 1483, 1517, 1551, 1583, 1615, 1645, 1674,
226 1703, 1730, 1757, 1782, 1806, 1829, 1851, 1872,
227 1892, 1911, 1928, 1945, 1960, 1974, 1987, 1998,
228 2009, 2018, 2026, 2033, 2038, 2042, 2046, 2047,
229 2048, 2047, 2046, 2042, 2038, 2033, 2026, 2018,
230 2009, 1998, 1987, 1974, 1960, 1945, 1928, 1911,
231 1892, 1872, 1851, 1829, 1806, 1782, 1757, 1730,
232 1703, 1674, 1645, 1615, 1583, 1551, 1517, 1483,
233 1448, 1412, 1375, 1338, 1299, 1260, 1220, 1179,
234 1138, 1096, 1053, 1009, 965, 921, 876, 830,
235 784, 737, 690, 642, 595, 546, 498, 449,
236 400, 350, 301, 251, 201, 151, 100, 50,
237 0, -50, -100, -151, -201, -251, -301, -350,
238 -400, -449, -498, -546, -595, -642, -690, -737,
239 -784, -830, -876, -921, -965, -1009, -1053, -1096,
240 -1138, -1179, -1220, -1260, -1299, -1338, -1375, -1412,
241 -1448, -1483, -1517, -1551, -1583, -1615, -1645, -1674,
242 -1703, -1730, -1757, -1782, -1806, -1829, -1851, -1872,
243 -1892, -1911, -1928, -1945, -1960, -1974, -1987, -1998,
244 -2009, -2018, -2026, -2033, -2038, -2042, -2046, -2047,
245 -2048, -2047, -2046, -2042, -2038, -2033, -2026, -2018,
246 -2009, -1998, -1987, -1974, -1960, -1945, -1928, -1911,
247 -1892, -1872, -1851, -1829, -1806, -1782, -1757, -1730,
248 -1703, -1674, -1645, -1615, -1583, -1551, -1517, -1483,
249 -1448, -1412, -1375, -1338, -1299, -1260, -1220, -1179,
250 -1138, -1096, -1053, -1009, -965, -921, -876, -830,
251 -784, -737, -690, -642, -595, -546, -498, -449,
252 -400, -350, -301, -251, -201, -151, -100, -50
253 };
254
freqrange(int x)255 static int freqrange(int x)
256 {
257 if (linearfreq)
258 return (x<-72*256)?-72*256:(x>96*256)?96*256:x;
259 else
260 return (x<107)?107:(x>438272)?438272:x;
261 }
262
volrange(int x)263 static int volrange(int x)
264 {
265 return (x<0)?0:(x>0x40)?0x40:x;
266 }
267
panrange(int x)268 static int panrange(int x)
269 {
270 return (x<0)?0:(x>0xFF)?0xFF:x;
271 }
272
273
ReadQue()274 static void ReadQue()
275 {
276 int type,val1,val2,t;
277 int i;
278 int time=mcpGet(-1, mcpGTimer);
279 while (1)
280 {
281 if (querpos==quewpos)
282 break;
283 if (time<que[querpos][0])
284 break;
285
286 t=que[querpos][0];
287 type=que[querpos][1];
288 val1=que[querpos][2];
289 val2=que[querpos][3];
290 querpos=(querpos+1)%quelen;
291
292 switch (type)
293 {
294 case queSync:
295 realsync=val2;
296 realsynctime=t;
297 channels[val1].chSync=val2;
298 channels[val1].chSyncTime=t;
299 break;
300 case quePos:
301 realpos=val2;
302 for (i=0; i<nchan; i++)
303 {
304 struct channel *c=&channels[i];
305 if (c->evpos==-1)
306 {
307 if (c->evpos0==realpos)
308 {
309 c->evpos=realpos;
310 c->evtime=t;
311 }
312 } else {
313 switch (c->evmodtype)
314 {
315 case 1:
316 c->evmodpos++;
317 break;
318 case 2:
319 if (!(realpos&0xFF))
320 c->evmodpos++;
321 break;
322 case 3:
323 if (!(realpos&0xFFFF))
324 c->evmodpos++;
325 break;
326 }
327 if ((c->evmodpos==c->evmod)&&c->evmod)
328 {
329 c->evmodpos=0;
330 c->evpos=realpos;
331 c->evtime=t;
332 }
333 }
334 }
335 break;
336 case queGVol: realgvol=val2; break;
337 case queTempo: realtempo=val2; break;
338 case queSpeed: realspeed=val2; break;
339 }
340 }
341 }
342
putque(int type,int val1,int val2)343 static void putque(int type, int val1, int val2)
344 {
345 if (((quewpos+1)%quelen)==querpos)
346 return;
347 que[quewpos][0]=cmdtime;
348 que[quewpos][1]=type;
349 que[quewpos][2]=val1;
350 que[quewpos][3]=val2;
351 quewpos=(quewpos+1)%quelen;
352 }
353
354
PlayNote(struct channel * ch)355 static void PlayNote(struct channel *ch)
356 {
357 int portatmp=0;
358 int delaytmp;
359 int keyoff=0;
360
361 if (proccmd==xmpCmdPortaNote)
362 portatmp=1;
363 if (proccmd==xmpCmdPortaVol)
364 portatmp=1;
365 if ((procvol>>4)==xmpVCmdPortaNote)
366 portatmp=1;
367
368 delaytmp=(proccmd==xmpCmdDelayNote)&&procdat;
369
370 if (procnot==97)
371 {
372 procnot=0;
373 procins=0;
374 keyoff=1;
375 }
376
377 if ((proccmd==xmpCmdKeyOff)&&!procdat)
378 keyoff=1;
379
380 if (!ch->chCurIns)
381 return;
382
383 if (ismod && !procnot && procins && ch->chCurIns!=ch->chLastIns)
384 procnot=ch->curnote;
385
386 if (procins && !keyoff && !delaytmp)
387 ch->chSustain=1;
388
389 if (procnot && !delaytmp)
390 ch->curnote=procnot;
391
392 if (procins && (ismod || !delaytmp))
393 {
394 int32_t checknote = ch->curnote;
395 if (!checknote)
396 checknote=49;
397 if (ismod)
398 ch->cursamp=&samples[ch->chCurIns-1];
399 else {
400 struct xmpinstrument *ins=&instruments[ch->chCurIns-1];
401 if (ins->samples[checknote-1]>nsamp)
402 return;
403 ch->cursamp=&samples[ins->samples[checknote-1]];
404 }
405 ch->chDefVol=(ch->cursamp->stdvol+1)>>2;
406 ch->chDefPan=ch->cursamp->stdpan;
407 }
408
409 if (procnot && !delaytmp)
410 {
411
412 if (!portatmp)
413 {
414 int32_t nn, frq;
415 ch->nextstop=1;
416 ch->notehit=1;
417
418 if (!ismod && procins)
419 {
420 struct xmpinstrument *ins=&instruments[ch->chCurIns-1];
421 if (ins->samples[ch->curnote-1]>nsamp)
422 return;
423 ch->cursamp=&samples[ins->samples[ch->curnote-1]];
424 ch->chDefVol=(ch->cursamp->stdvol+1)>>2;
425 ch->chDefPan=ch->cursamp->stdpan;
426 }
427
428 if (ch->cursamp)
429 {
430 ch->nextsamp=ch->cursamp->handle;
431
432 nn=ch->cursamp->normnote;
433 if (proccmd==xmpCmdSFinetune)
434 {
435 nn=ch->cursamp->normtrans-(int16_t)(procdat<<4)+0x80;
436 ch->fx=xfxSetFinetune;
437 }
438
439 ch->chCurNormNote=nn;
440 } else {
441 /* if we have no sample yet, just do as much as we can */
442 if (proccmd==xmpCmdSFinetune)
443 ch->fx=xfxSetFinetune;
444 }
445
446 frq=48*256-(((procnot-1)<<8)-ch->chCurNormNote);
447 if (!linearfreq)
448 frq=mcpGetFreq6848(frq);
449 ch->chPitch=frq;
450 ch->chFinalPitch=frq;
451 ch->chPortaToPitch=frq;
452
453 ch->nextpos=0;
454
455 if (proccmd==xmpCmdOffset)
456 {
457 if (procdat!=0)
458 ch->chOffset=procdat;
459 ch->nextpos=ch->chOffset<<8;
460 if (ismod && ch->nextpos>sampleinfos[ch->nextsamp].length)
461 ch->nextpos=sampleinfos[ch->nextsamp].length-16;
462 ch->fx=xfxOffset;
463 }
464
465 ch->chVibPos=0;
466 ch->chTremPos=0;
467 ch->chArpPos=0;
468 ch->chMRetrigPos=0;
469 ch->chTremorPos=0;
470 } else {
471 int32_t frq=48*256-(((procnot-1)<<8)-ch->chCurNormNote);
472 if (!linearfreq)
473 frq=mcpGetFreq6848(frq);
474 ch->chPortaToPitch=frq;
475 }
476 }
477
478 if (procnot && delaytmp && !ismod)
479 return;
480
481 if (keyoff&&ch->cursamp)
482 {
483 ch->chSustain=0;
484 if ((ch->cursamp->volenv>=nenv)&&!procins)
485 ch->chFadeVol=0;
486 }
487
488 if (procins && (ismod || ch->chSustain))
489 {
490 ch->chVol=ch->chDefVol;
491 ch->chFinalVol=ch->chDefVol;
492 if (ch->chDefPan!=-1)
493 {
494 ch->chPan=ch->chDefPan;
495 ch->chFinalPan=ch->chDefPan;
496 }
497 ch->chFadeVol=0x8000;
498 ch->chAVibPos=0;
499 ch->chAVibSwpPos=0;
500 ch->chVolEnvPos=0;
501 ch->chPanEnvPos=0;
502 }
503 }
504
505 static uint16_t notetab[16]={32768,30929,29193,27554,26008,24548,23170,21870,20643,19484,18390,17358,16384,15464,14596,13777};
506
xmpPlayTick(void)507 static void xmpPlayTick(void)
508 {
509 int i;
510 struct xmpsample *sm;
511 int vol, pan;
512
513 if (firstspeed)
514 {
515 mcpSet(-1, mcpGSpeed, firstspeed);
516 firstspeed=0;
517 }
518
519 cmdtime=mcpGet(-1, mcpGCmdTimer);
520 ReadQue();
521
522 tick0=0;
523 for (i=0; i<nchan; i++)
524 {
525 struct channel *ch=&channels[i];
526 ch->chFinalVol=ch->chVol;
527 ch->chFinalPan=ch->chPan;
528 ch->chFinalPitch=ch->chPitch;
529 ch->nextstop=0;
530 ch->nextsamp=-1;
531 ch->nextpos=-1;
532 }
533
534 curtick++;
535 if (curtick>=curtempo)
536 curtick=0;
537
538 if (!curtick&&patdelay)
539 {
540 if (jumptoord!=-1)
541 {
542 if (jumptoord!=curord)
543 for (i=0; i<nchan; i++)
544 {
545 struct channel *ch=&channels[i];
546 ch->chPatLoopCount=0;
547 ch->chPatLoopStart=0;
548 }
549
550 if (jumptoord>=nord)
551 {
552 jumptoord=loopord;
553 if (!usersetpos)
554 looped=1;
555 }
556 if ((jumptoord<curord)&&!usersetpos)
557 looped=1;
558 usersetpos=0;
559
560 curord=jumptoord;
561 currow=jumptorow;
562 jumptoord=-1;
563 jumptorow=0;
564 patlen=patlens[orders[curord]];
565 patptr=patterns[orders[curord]];
566 }
567 }
568
569 if (!curtick && (!patdelay || ismod))
570 {
571 // no more ticks, we need to step
572 tick0=1;
573
574 if (!patdelay)
575 {
576 currow++;
577 // no jump configured? and at the end of row? jump to the next order, and start fresh
578 if ((jumptoord==-1)&&(currow>=patlen))
579 {
580 jumptoord=curord+1;
581 jumptorow=nextpatternrow;
582 nextpatternrow=0;
583 }
584 // jump is configured
585 if (jumptoord!=-1)
586 {
587 // jump is not the same order.. (jump is not caused by a loop)
588 if (jumptoord!=curord)
589 for (i=0; i<nchan; i++)
590 { // reset all loop counters
591 struct channel *ch=&channels[i];
592 ch->chPatLoopCount=0;
593 ch->chPatLoopStart=0;
594 }
595
596 // jumping into/beyond EOF, loop module
597 if (jumptoord>=nord)
598 {
599 jumptoord=loopord;
600 }
601 // if jump is backwards, song has globally looped, flag it for the UI
602 if ((jumptoord<curord)&&!usersetpos)
603 looped=1;
604 usersetpos=0;
605
606 // take the position, and clear jumptoord
607 curord=jumptoord;
608 currow=jumptorow;
609 jumptoord=-1;
610 jumptorow=0;
611 patlen=patlens[orders[curord]];
612 patptr=patterns[orders[curord]];
613 }
614 }
615
616 for (i=0; i<nchan; i++)
617 {
618 struct channel *ch=&channels[i];
619
620 ch->notehit=0;
621 ch->volslide=0;
622 ch->pitchslide=0;
623 ch->panslide=0;
624 ch->pitchfx=0;
625 ch->volfx=0;
626 ch->notefx=0;
627 ch->fx=0;
628
629 procnot=patptr[nchan*currow+i][0];
630 procins=patptr[nchan*currow+i][1];
631 procvol=patptr[nchan*currow+i][2];
632 proccmd=patptr[nchan*currow+i][3];
633 procdat=patptr[nchan*currow+i][4];
634
635 if (!patdelay)
636 {
637 if (procnot==97)
638 procins=0;
639 if (procins && procins<=ninst)
640 {
641 ch->chLastIns=ch->chCurIns;
642 ch->chCurIns=procins;
643 }
644 if (procins<=ninst)
645 PlayNote(ch);
646 }
647
648 ch->chVCommand=procvol>>4;
649
650 switch (ch->chVCommand)
651 {
652 case xmpVCmdVol0x: case xmpVCmdVol1x: case xmpVCmdVol2x: case xmpVCmdVol3x:
653 if ((proccmd!=xmpCmdDelayNote)||!procdat)
654 ch->chFinalVol=ch->chVol=procvol-0x10;
655 break;
656 case xmpVCmdVol40:
657 if ((proccmd!=xmpCmdDelayNote)||!procdat)
658 ch->chFinalVol=ch->chVol=0x40;
659 break;
660 case xmpVCmdVolSlideD: case xmpVCmdVolSlideU: case xmpVCmdPanSlideL: case xmpVCmdPanSlideR:
661 ch->chVVolPanSlideVal=procvol&0xF;
662 break;
663 case xmpVCmdFVolSlideD:
664 if ((proccmd!=xmpCmdDelayNote)||!procdat)
665 ch->chFinalVol=ch->chVol=volrange(ch->chVol-(procvol&0xF));
666 ch->fx=xfxRowVolSlideDown;
667 break;
668 case xmpVCmdFVolSlideU:
669 if ((proccmd!=xmpCmdDelayNote)||!procdat)
670 ch->chFinalVol=ch->chVol=volrange(ch->chVol+(procvol&0xF));
671 ch->fx=xfxRowVolSlideUp;
672 break;
673 case xmpVCmdVibRate:
674 if (procvol&0xF)
675 ch->chVibRate=((procvol&0xF)<<2);
676 break;
677 case xmpVCmdVibDep:
678 ch->pitchfx=xfxPXVibrato;
679 if (procvol&0xF)
680 ch->chVibDep=((procvol&0xF)<<(1+!linearfreq));
681 break;
682 case xmpVCmdPanning:
683 if ((proccmd!=xmpCmdDelayNote)||!procdat)
684 ch->chFinalPan=ch->chPan=(procvol&0xF)*0x11;
685 break;
686 case xmpVCmdPortaNote:
687 ch->pitchslide=xfxPSToNote;
688 if (procvol&0xF)
689 ch->chPortaToVal=(procvol&0xF)<<8;
690 break;
691 }
692
693 ch->chCommand=proccmd;
694 switch (ch->chCommand)
695 {
696 case xmpCmdArpeggio:
697 if (!procdat)
698 ch->chCommand=0xFF;
699 else {
700 ch->pitchfx=xfxPXArpeggio;
701 ch->fx=xfxArpeggio;
702 }
703 ch->chArpNotes[0]=0;
704 ch->chArpNotes[1]=procdat>>4;
705 ch->chArpNotes[2]=procdat&0xF;
706 break;
707 case xmpCmdPortaU:
708 if (procdat)
709 ch->chPortaUVal=procdat<<4;
710 ch->pitchslide=xfxPSUp;
711 ch->fx=xfxPitchSlideUp;
712 break;
713 case xmpCmdPortaD:
714 if (procdat)
715 ch->chPortaDVal=procdat<<4;
716 ch->pitchslide=xfxPSDown;
717 ch->fx=xfxPitchSlideDown;
718 break;
719 case xmpCmdPortaNote:
720 if (procdat)
721 ch->chPortaToVal=procdat<<4;
722 ch->pitchslide=xfxPSToNote;
723 ch->fx=xfxPitchSlideToNote;
724 break;
725 case xmpCmdVibrato:
726 ch->pitchfx=xfxPXVibrato;
727 ch->fx=xfxPitchVibrato;
728 if (procdat&0xF)
729 ch->chVibDep=(procdat&0xF)<<(1+!linearfreq);
730 if (procdat&0xF0)
731 ch->chVibRate=(procdat>>4)<<2;
732 break;
733 case xmpCmdPortaVol: case xmpCmdVibVol: case xmpCmdVolSlide:
734 if (procdat || ismod)
735 ch->chVolSlideVal=procdat;
736 if (ch->chVolSlideVal&0xf0)
737 {
738 ch->volslide=xfxVSUp;
739 ch->fx=xfxVolSlideUp;
740 } else if (ch->chVolSlideVal&0x0f)
741 {
742 ch->volslide=xfxVSDown;
743 ch->fx=xfxVolSlideDown;
744 }
745 break;
746 case xmpCmdTremolo:
747 ch->volfx=xfxVXVibrato;
748 ch->fx=xfxVolVibrato;
749 if (procdat&0xF)
750 ch->chTremDep=(procdat&0xF)<<2;
751 if (procdat&0xF0)
752 ch->chTremRate=(procdat>>4)<<2;
753 break;
754 case xmpCmdPanning:
755 ch->chFinalPan=ch->chPan=procdat;
756 break;
757 case xmpCmdJump:
758 if (!patdelay)
759 {
760 jumptoord=procdat;
761 jumptorow=0;
762 nextpatternrow=0;
763 }
764 break;
765 case xmpCmdVolume:
766 ch->chFinalVol=ch->chVol=volrange(procdat);
767 break;
768 case xmpCmdBreak:
769 if (!patdelay)
770 {
771 if (jumptoord==-1)
772 jumptoord=curord+1;
773 jumptorow=(procdat&0xF)+(procdat>>4)*10;
774 nextpatternrow=0;
775 }
776 break;
777 case xmpCmdSpeed:
778 if (!procdat)
779 {
780 jumptoord=0;
781 jumptorow=0;
782 break;
783 }
784 if (procdat>=0x20)
785 {
786 curbpm=procdat;
787 mcpSet(-1, mcpGSpeed, 256*2*curbpm/5);
788 putque(queTempo, -1, curbpm);
789 } else {
790 curtempo=procdat;
791 putque(queSpeed, -1, curtempo);
792 }
793 break;
794 case xmpCmdMODtTempo:
795 if (!procdat)
796 {
797 jumptoord=procdat;
798 jumptorow=0;
799 } else {
800 curtempo=procdat;
801 putque(queSpeed, -1, curtempo);
802 }
803 break;
804 case xmpCmdGVolume:
805 globalvol=volrange(procdat);
806 putque(queGVol, -1, globalvol);
807 break;
808 case xmpCmdGVolSlide:
809 if (procdat)
810 ch->chGVolSlideVal=procdat;
811 if (ch->chGVolSlideVal&0xf0)
812 globalfx=xfxGVSUp;
813 else if (ch->chGVolSlideVal&0x0f)
814 globalfx=xfxGVSDown;
815 break;
816 case xmpCmdKeyOff:
817 ch->chActionTick=procdat;
818 break;
819 case xmpCmdRetrigger:
820 ch->notefx=xfxNXRetrig;
821 ch->fx=xfxRetrig;
822 ch->chActionTick=procdat;
823 break;
824 case xmpCmdNoteCut:
825 ch->notefx=xfxNXNoteCut;
826 ch->fx=xfxNoteCut;
827 ch->chActionTick=procdat;
828 break;
829 case xmpCmdEnvPos:
830 ch->chVolEnvPos=ch->chPanEnvPos=procdat;
831 ch->fx=xfxEnvPos;
832 if (ch->cursamp)
833 {
834 if (ch->cursamp->volenv<nenv)
835 if (ch->chVolEnvPos>envelopes[ch->cursamp->volenv].len)
836 ch->chVolEnvPos=envelopes[ch->cursamp->volenv].len;
837 if (ch->cursamp->panenv<nenv)
838 if (ch->chPanEnvPos>envelopes[ch->cursamp->panenv].len)
839 ch->chPanEnvPos=envelopes[ch->cursamp->panenv].len;
840 } else
841 fprintf(stderr, __FILE__ " CmdEnvPos ch->cursamp not set\n");
842 break;
843 case xmpCmdPanSlide:
844 if (procdat)
845 ch->chPanSlideVal=procdat;
846 if (ch->chPanSlideVal&0xF0)
847 ch->panslide=xfxPnSLeft;
848 else if (ch->chPanSlideVal&0x0F)
849 ch->panslide=xfxPnSRight;
850 break;
851 case xmpCmdMRetrigger:
852 ch->notefx=xfxNXRetrig;
853 ch->fx=xfxRetrig;
854 if (procdat)
855 {
856 ch->chMRetrigLen=procdat&0xF;
857 ch->chMRetrigAct=procdat>>4;
858 }
859 break;
860 case xmpCmdSync1: case xmpCmdSync2: case xmpCmdSync3:
861 putque(queSync, i, procdat);
862 break;
863 case xmpCmdTremor:
864 ch->volfx=xfxVXTremor;
865 ch->fx=xfxTremor;
866 if (procdat)
867 {
868 ch->chTremorLen=(procdat&0xF)+(procdat>>4)+2;
869 ch->chTremorOff=(procdat>>4)+1;
870 ch->chTremorPos=0;
871 }
872 break;
873 case xmpCmdXPorta:
874 if ((procdat>>4)==1)
875 {
876 if (procdat&0xF)
877 ch->chXFinePortaUVal=procdat&0xF;
878 ch->chFinalPitch=ch->chPitch=freqrange(ch->chPitch-(ch->chXFinePortaUVal<<2));
879 } else if ((procdat>>4)==2)
880 {
881 if (procdat&0xF)
882 ch->chXFinePortaDVal=procdat&0xF;
883 ch->chFinalPitch=ch->chPitch=freqrange(ch->chPitch+(ch->chXFinePortaDVal<<2));
884 }
885 break;
886 case xmpCmdFPortaU:
887 if (procdat)
888 ch->chFinePortaUVal=procdat;
889 ch->fx=xfxRowPitchSlideUp;
890 ch->chFinalPitch=ch->chPitch=freqrange(ch->chPitch-(ch->chFinePortaUVal<<4));
891 break;
892 case xmpCmdFPortaD:
893 if (procdat)
894 ch->chFinePortaDVal=procdat;
895 ch->fx=xfxRowPitchSlideDown;
896 ch->chFinalPitch=ch->chPitch=freqrange(ch->chPitch+(ch->chFinePortaDVal<<4));
897 break;
898 case xmpCmdGlissando:
899 ch->chGlissando=procdat;
900 break;
901 case xmpCmdVibType:
902 ch->chVibType=procdat&3;
903 break;
904 case xmpCmdPatLoop:
905 /* if(plLoopPatterns)*/ /* TODO ?? */
906 {
907 if (!procdat)
908 {
909 ch->chPatLoopStart=currow;
910 if (ft2_e60bug)
911 {
912 nextpatternrow=currow;
913 }
914 } else {
915 ch->chPatLoopCount++;
916 if (ch->chPatLoopCount<=procdat)
917 {
918 jumptorow=ch->chPatLoopStart;
919 jumptoord=curord;
920 } else {
921 ch->chPatLoopCount=0;
922 ch->chPatLoopStart=currow+1;
923 }
924 }
925 }
926 break;
927 case xmpCmdTremType:
928 ch->chTremType=procdat&3;
929 break;
930 case xmpCmdSPanning:
931 ch->chFinalPan=ch->chPan=procdat*0x11;
932 break;
933 case xmpCmdFVolSlideU:
934 if (procdat || ismod )
935 ch->chFineVolSlideUVal=procdat;
936 ch->fx=xfxRowVolSlideUp;
937 ch->chFinalVol=ch->chVol=volrange(ch->chVol+ch->chFineVolSlideUVal);
938 break;
939 case xmpCmdFVolSlideD:
940 if (procdat || ismod )
941 ch->chFineVolSlideDVal=procdat;
942 ch->fx=xfxRowVolSlideDown;
943 ch->chFinalVol=ch->chVol=volrange(ch->chVol-ch->chFineVolSlideDVal);
944 break;
945 case xmpCmdPatDelay:
946 if (!patdelay)
947 patdelay=procdat+1;
948 break;
949 case xmpCmdDelayNote:
950 if (procnot)
951 ch->chDelayNote=procnot;
952 ch->fx=xfxDelay;
953 ch->notefx=xfxNXDelay;
954 ch->chDelayIns=procins;
955 ch->chDelayVol=procvol;
956 ch->chActionTick=procdat;
957 break;
958 }
959 }
960 }
961 if (!curtick&&patdelay)
962 {
963 patdelay--;
964 }
965
966 for (i=0; i<nchan; i++)
967 {
968 struct channel *ch=&channels[i];
969
970 switch (ch->chVCommand)
971 {
972 case xmpVCmdVolSlideD:
973 ch->volslide=xfxVSDown;
974 if (tick0)
975 break;
976 ch->chFinalVol=ch->chVol=volrange(ch->chVol-ch->chVVolPanSlideVal);
977 break;
978 case xmpVCmdVolSlideU:
979 ch->volslide=xfxVSUp;
980 if (tick0)
981 break;
982 ch->chFinalVol=ch->chVol=volrange(ch->chVol+ch->chVVolPanSlideVal);
983 break;
984 case xmpVCmdVibDep: /* FICKEN */
985 switch (ch->chVibType)
986 {
987 case 0:
988 ch->chFinalPitch=freqrange((( sintab[ch->chVibPos] *ch->chVibDep)>>7)+ch->chPitch);
989 break;
990 case 1:
991 ch->chFinalPitch=freqrange((( (ch->chVibPos-0x80) *ch->chVibDep)>>3)+ch->chPitch);
992 break;
993 case 2:
994 ch->chFinalPitch=freqrange((( ((ch->chVibPos&0x80)-0x40) *ch->chVibDep)>>2)+ch->chPitch);
995 break;
996 }
997 if (!tick0)
998 ch->chVibPos+=ch->chVibRate;
999 break;
1000 case xmpVCmdPanSlideL:
1001 if (tick0)
1002 break;
1003 ch->chFinalPan=ch->chPan=panrange(ch->chPan-ch->chVVolPanSlideVal);
1004 break;
1005 case xmpVCmdPanSlideR:
1006 if (tick0)
1007 break;
1008 ch->chFinalPan=ch->chPan=panrange(ch->chPan+ch->chVVolPanSlideVal);
1009 break;
1010 case xmpVCmdPortaNote:
1011 if (!tick0)
1012 {
1013 if (ch->chPitch<ch->chPortaToPitch)
1014 {
1015 ch->chPitch+=ch->chPortaToVal;
1016 if (ch->chPitch>ch->chPortaToPitch)
1017 ch->chPitch=ch->chPortaToPitch;
1018 } else {
1019 ch->chPitch-=ch->chPortaToVal;
1020 if (ch->chPitch<ch->chPortaToPitch)
1021 ch->chPitch=ch->chPortaToPitch;
1022 }
1023 }
1024 if (ch->chGlissando)
1025 {
1026 if (linearfreq)
1027 {
1028 ch->chFinalPitch=((ch->chPitch+ch->chCurNormNote+0x80)&~0xFF)-ch->chCurNormNote;
1029 } else {
1030 ch->chFinalPitch=mcpGetFreq6848(((mcpGetNote6848(ch->chPitch)+ch->chCurNormNote+0x80)&~0xFF)-ch->chCurNormNote);
1031 }
1032 } else
1033 ch->chFinalPitch=ch->chPitch;
1034 break;
1035 }
1036
1037 switch (ch->chCommand)
1038 {
1039 case xmpCmdArpeggio:
1040 if (linearfreq)
1041 ch->chFinalPitch=freqrange(ch->chPitch-(ch->chArpNotes[ch->chArpPos]<<8));
1042 else
1043 ch->chFinalPitch=freqrange((ch->chPitch*notetab[ch->chArpNotes[ch->chArpPos]])>>15);
1044 ch->chArpPos++;
1045 if (ch->chArpPos==3)
1046 ch->chArpPos=0;
1047 break;
1048 case xmpCmdPortaU:
1049 if (tick0)
1050 break;
1051 ch->chFinalPitch=ch->chPitch=freqrange(ch->chPitch-ch->chPortaUVal);
1052 break;
1053 case xmpCmdPortaD:
1054 if (tick0)
1055 break;
1056 ch->chFinalPitch=ch->chPitch=freqrange(ch->chPitch+ch->chPortaDVal);
1057 break;
1058 case xmpCmdPortaNote:
1059 if (!tick0)
1060 {
1061 if (ch->chPitch<ch->chPortaToPitch)
1062 {
1063 ch->chPitch+=ch->chPortaToVal;
1064 if (ch->chPitch>ch->chPortaToPitch)
1065 ch->chPitch=ch->chPortaToPitch;
1066 } else {
1067 ch->chPitch-=ch->chPortaToVal;
1068 if (ch->chPitch<ch->chPortaToPitch)
1069 ch->chPitch=ch->chPortaToPitch;
1070 }
1071 }
1072 if (ch->chGlissando)
1073 {
1074 if (linearfreq)
1075 ch->chFinalPitch=((ch->chPitch+ch->chCurNormNote+0x80)&~0xFF)-ch->chCurNormNote;
1076 else
1077 ch->chFinalPitch=mcpGetFreq6848(((mcpGetNote6848(ch->chPitch)+ch->chCurNormNote+0x80)&~0xFF)-ch->chCurNormNote);
1078 } else
1079 ch->chFinalPitch=ch->chPitch;
1080 break;
1081 case xmpCmdVibrato:
1082 switch (ch->chVibType)
1083 {
1084 case 0:
1085 ch->chFinalPitch=freqrange((( sintab[ch->chVibPos] *ch->chVibDep)>>8)+ch->chPitch);
1086 break;
1087 case 1:
1088 ch->chFinalPitch=freqrange((( (ch->chVibPos-0x80) *ch->chVibDep)>>4)+ch->chPitch);
1089 break;
1090 case 2:
1091 ch->chFinalPitch=freqrange((( ((ch->chVibPos&0x80)-0x40) *ch->chVibDep)>>3)+ch->chPitch);
1092 break;
1093 }
1094 if (!tick0)
1095 ch->chVibPos+=ch->chVibRate;
1096 break;
1097 case xmpCmdPortaVol:
1098 if (!tick0)
1099 {
1100 if (ch->chPitch<ch->chPortaToPitch)
1101 {
1102 ch->chPitch+=ch->chPortaToVal;
1103 if (ch->chPitch>ch->chPortaToPitch)
1104 ch->chPitch=ch->chPortaToPitch;
1105 } else {
1106 ch->chPitch-=ch->chPortaToVal;
1107 if (ch->chPitch<ch->chPortaToPitch)
1108 ch->chPitch=ch->chPortaToPitch;
1109 }
1110 }
1111 if (ch->chGlissando)
1112 {
1113 if (linearfreq)
1114 ch->chFinalPitch=((ch->chPitch+ch->chCurNormNote+0x80)&~0xFF)-ch->chCurNormNote;
1115 else
1116 ch->chFinalPitch=mcpGetFreq6848(((mcpGetNote6848(ch->chPitch)+ch->chCurNormNote+0x80)&~0xFF)-ch->chCurNormNote);
1117 } else
1118 ch->chFinalPitch=ch->chPitch;
1119
1120 if (tick0)
1121 break;
1122 ch->chFinalVol=ch->chVol=volrange(ch->chVol+((ch->chVolSlideVal&0xF0)?(ch->chVolSlideVal>>4):-(ch->chVolSlideVal&0xF)));
1123 break;
1124 case xmpCmdVibVol:
1125 switch (ch->chVibType)
1126 {
1127 case 0:
1128 ch->chFinalPitch=freqrange((( sintab[ch->chVibPos] *ch->chVibDep)>>8)+ch->chPitch);
1129 break;
1130 case 1:
1131 ch->chFinalPitch=freqrange((( (ch->chVibPos-0x80) *ch->chVibDep)>>4)+ch->chPitch);
1132 break;
1133 case 2:
1134 ch->chFinalPitch=freqrange((( ((ch->chVibPos&0x80)-0x40) *ch->chVibDep)>>3)+ch->chPitch);
1135 break;
1136 }
1137 if (!tick0)
1138 ch->chVibPos+=ch->chVibRate;
1139
1140 if (tick0)
1141 break;
1142 ch->chFinalVol=ch->chVol=volrange(ch->chVol+((ch->chVolSlideVal&0xF0)?(ch->chVolSlideVal>>4):-(ch->chVolSlideVal&0xF)));
1143 break;
1144 case xmpCmdTremolo:
1145 switch (ch->chTremType)
1146 {
1147 case 0:
1148 ch->chFinalVol+=(( sintab[ch->chTremPos] *ch->chTremDep)>>11);
1149 break;
1150 case 1:
1151 ch->chFinalVol+=(( (ch->chTremPos-0x80) *ch->chTremDep)>>7);
1152 break;
1153 case 2:
1154 ch->chFinalVol+=(( ((ch->chTremPos&0x80)-0x40) *ch->chTremDep)>>6);
1155 break;
1156 }
1157 ch->chFinalVol=volrange(ch->chFinalVol);
1158 if (!tick0)
1159 ch->chTremPos+=ch->chTremRate;
1160 break;
1161 case xmpCmdVolSlide:
1162 if (tick0)
1163 break;
1164 ch->chFinalVol=ch->chVol=volrange(ch->chVol+((ch->chVolSlideVal&0xF0)?(ch->chVolSlideVal>>4):-(ch->chVolSlideVal&0xF)));
1165 break;
1166 case xmpCmdGVolSlide:
1167 if (tick0)
1168 break;
1169 if (ch->chGVolSlideVal&0xF0)
1170 globalvol=volrange(globalvol+(ch->chGVolSlideVal>>4));
1171 else
1172 globalvol=volrange(globalvol-(ch->chGVolSlideVal&0xF));
1173 putque(queGVol, -1, globalvol);
1174 break;
1175 case xmpCmdKeyOff:
1176 if (tick0)
1177 break;
1178 if (curtick==ch->chActionTick)
1179 {
1180 ch->chSustain=0;
1181 if (ch->cursamp&&(ch->cursamp->volenv>=nenv))
1182 ch->chFadeVol=0;
1183 }
1184 break;
1185 case xmpCmdPanSlide:
1186 if (tick0)
1187 break;
1188 ch->chFinalPan=ch->chPan=panrange(ch->chPan+((ch->chPanSlideVal&0xF0)?(ch->chPanSlideVal>>4):-(ch->chPanSlideVal&0xF)));
1189 break;
1190 case xmpCmdMRetrigger:
1191 if (ch->chMRetrigPos++!=ch->chMRetrigLen)
1192 break;
1193 ch->chMRetrigPos=1;
1194 ch->nextpos=0;
1195 ch->chVolEnvPos=0;
1196 ch->chPanEnvPos=0;
1197
1198 switch (ch->chMRetrigAct)
1199 {
1200 case 0: case 8: break;
1201 case 1: case 2: case 3: case 4: case 5:
1202 ch->chVol=ch->chVol-(1<<(ch->chMRetrigAct-1));
1203 break;
1204 case 9: case 10: case 11: case 12: case 13:
1205 ch->chVol=ch->chVol+(1<<(ch->chMRetrigAct-9));
1206 break;
1207 case 6: ch->chVol=(ch->chVol*5)>>3; break;
1208 case 14: ch->chVol=(ch->chVol*3)>>1; break;
1209 case 7: ch->chVol>>=1; break;
1210 case 15: ch->chVol<<=1; break;
1211 }
1212 ch->chFinalVol=ch->chVol=volrange(ch->chVol);
1213 break;
1214 case xmpCmdTremor:
1215 if (ch->chTremorPos>=ch->chTremorOff)
1216 ch->chFinalVol=0;
1217 if (tick0)
1218 break;
1219 ch->chTremorPos++;
1220 if (ch->chTremorPos==ch->chTremorLen)
1221 ch->chTremorPos=0;
1222 break;
1223 case xmpCmdRetrigger:
1224 if (!ch->chActionTick)
1225 break;
1226 if (!(curtick%ch->chActionTick))
1227 {
1228 ch->nextpos=0;
1229 ch->chVolEnvPos=0;
1230 ch->chPanEnvPos=0;
1231 }
1232
1233 break;
1234 case xmpCmdNoteCut:
1235 if (tick0)
1236 break;
1237 if (curtick==ch->chActionTick)
1238 ch->chFinalVol=ch->chVol=0;
1239 break;
1240 case xmpCmdDelayNote:
1241 if (tick0)
1242 break;
1243 if (curtick!=ch->chActionTick)
1244 break;
1245 procnot=ch->chDelayNote;
1246 procins=ch->chDelayIns;
1247 proccmd=0;
1248 procdat=0;
1249 procvol=0;
1250 PlayNote(ch);
1251 switch (ch->chDelayVol>>4)
1252 {
1253 case xmpVCmdVol0x: case xmpVCmdVol1x: case xmpVCmdVol2x: case xmpVCmdVol3x:
1254 ch->chFinalVol=ch->chVol=ch->chDelayVol-0x10;
1255 break;
1256 case xmpVCmdVol40:
1257 ch->chFinalVol=ch->chVol=0x40;
1258 break;
1259 case xmpVCmdPanning:
1260 ch->chFinalPan=ch->chPan=(ch->chDelayVol&0xF)*0x11;
1261 break;
1262 }
1263 break;
1264 }
1265
1266 if (!ch->cursamp)
1267 {
1268 mcpSet(i, mcpCStatus, 0);
1269 continue;
1270 }
1271
1272 sm=ch->cursamp;
1273
1274 vol=(ch->chFinalVol*globalvol)>>4;
1275 pan=ch->chFinalPan-128;
1276 if (!ch->chSustain)
1277 {
1278 vol=(vol*ch->chFadeVol)>>15;
1279 if (ch->chFadeVol>=sm->volfade)
1280 ch->chFadeVol-=sm->volfade;
1281 else
1282 ch->chFadeVol=0;
1283 }
1284
1285 if (sm->volenv<nenv)
1286 {
1287 const struct xmpenvelope *env=&envelopes[sm->volenv];
1288 vol=(env->env[ch->chVolEnvPos]*vol)>>8;
1289
1290 if (ch->chVolEnvPos<env->len)
1291 if (!ch->chSustain || !(env->type&xmpEnvSLoop) || ch->chVolEnvPos!=env->sustain)
1292 {
1293 ch->chVolEnvPos++;
1294 if (env->type&xmpEnvLoop)
1295 {
1296 if (ch->chVolEnvPos==env->loope && (ch->chSustain || env->loope!=env->sustain))
1297 ch->chVolEnvPos=env->loops;
1298 }
1299 }
1300 }
1301
1302 if (sm->panenv<nenv)
1303 {
1304 const struct xmpenvelope *env=&envelopes[sm->panenv];
1305 pan+=((env->env[ch->chPanEnvPos]-128)*(128-((pan<0)?-pan:pan)))>>7;
1306
1307 if (ch->chPanEnvPos<env->len)
1308 if (!ch->chSustain || !(env->type&xmpEnvSLoop) || ch->chPanEnvPos!=env->sustain)
1309 {
1310 ch->chPanEnvPos++;
1311 if (env->type&xmpEnvLoop)
1312 {
1313 if (ch->chVolEnvPos==env->loope && (ch->chSustain || env->loope!=env->sustain))
1314 ch->chPanEnvPos=env->loops;
1315 }
1316 }
1317 }
1318
1319 if (sm->vibrate&&sm->vibdepth)
1320 {
1321 int dep=0;
1322 switch (sm->vibtype)
1323 {
1324 case 0:
1325 dep=(sintab[ch->chAVibPos>>8]*sm->vibdepth)>>11;
1326 break;
1327 case 1:
1328 dep=(ch->chAVibPos&0x8000)?-sm->vibdepth:sm->vibdepth;
1329 break;
1330 case 2:
1331 dep=(sm->vibdepth*(32768-ch->chAVibPos))>>14;
1332 break;
1333 case 3:
1334 dep=(sm->vibdepth*(ch->chAVibPos-32768))>>14;
1335 break;
1336 }
1337
1338 ch->chAVibSwpPos+=sm->vibsweep;
1339 if (ch->chAVibSwpPos>0x10000)
1340 ch->chAVibSwpPos=0x10000;
1341 dep=(dep*(int)ch->chAVibSwpPos)>>17;
1342
1343 ch->chFinalPitch-=dep;
1344
1345 ch->chAVibPos+=sm->vibrate;
1346 }
1347
1348 if (ch->nextstop)
1349 mcpSet(i, mcpCStatus, 0);
1350 if (ch->nextsamp!=(unsigned)-1)
1351 mcpSet(i, mcpCInstrument, ch->nextsamp);
1352 if (ch->nextpos!=(unsigned)-1)
1353 {
1354 mcpSet(i, mcpCPosition, ch->nextpos);
1355 mcpSet(i, mcpCLoop, 1);
1356 mcpSet(i, mcpCDirect, 0);
1357 mcpSet(i, mcpCStatus, 1);
1358 }
1359 if (linearfreq)
1360 mcpSet(i, mcpCPitch, -ch->chFinalPitch);
1361 else
1362 mcpSet(i, mcpCPitch6848, ch->chFinalPitch);
1363 mcpSet(i, mcpCVolume, (looping||!looped)?vol:0);
1364 mcpSet(i, mcpCPanning, pan);
1365 mcpSet(i, mcpCMute, mutech[i]);
1366 }
1367 putque(quePos, -1, curtick|(curord<<16)|(currow<<8));
1368 }
1369
xmpGetRealPos(void)1370 int __attribute__ ((visibility ("internal"))) xmpGetRealPos(void)
1371 {
1372 ReadQue();
1373 return realpos;
1374 }
1375
xmpChanActive(int ch)1376 int __attribute__ ((visibility ("internal"))) xmpChanActive(int ch)
1377 {
1378 return mcpGet(ch, mcpCStatus)&&channels[ch].cursamp&&channels[ch].chVol&&channels[ch].chFadeVol;
1379 }
1380
xmpGetChanIns(int ch)1381 int __attribute__ ((visibility ("internal"))) xmpGetChanIns(int ch)
1382 {
1383 return channels[ch].chCurIns;
1384 }
1385
xmpGetChanSamp(int ch)1386 int __attribute__ ((visibility ("internal"))) xmpGetChanSamp(int ch)
1387 {
1388 if (!channels[ch].cursamp)
1389 return 0xFFFF;
1390 return channels[ch].cursamp-samples;
1391 }
1392
xmpGetDotsData(int ch,int * smp,int * frq,int * voll,int * volr,int * sus)1393 int __attribute__ ((visibility ("internal"))) xmpGetDotsData(int ch, int *smp, int *frq, int *voll, int *volr, int *sus)
1394 {
1395 struct channel *c;
1396
1397 if (!mcpGet(ch, mcpCStatus))
1398 return 0;
1399 c=&channels[ch];
1400 if (!c->cursamp||!c->chVol||!c->chFadeVol)
1401 return 0;
1402 *smp=c->cursamp-samples;
1403 if (linearfreq)
1404 *frq=60*256+c->cursamp->normnote-freqrange(c->chFinalPitch);
1405 else
1406 *frq=60*256+c->cursamp->normnote+mcpGetNote8363(6848*8363/freqrange(c->chFinalPitch));
1407 mcpGetRealVolume(ch, voll, volr);
1408 *sus=c->chSustain;
1409 return 1;
1410 }
1411
xmpGetRealVolume(int ch,int * voll,int * volr)1412 void __attribute__ ((visibility ("internal"))) xmpGetRealVolume(int ch, int *voll, int *volr)
1413 {
1414 mcpGetRealVolume(ch, voll, volr);
1415 }
1416
xmpGetPos(void)1417 uint16_t __attribute__ ((visibility ("internal"))) xmpGetPos(void)
1418 {
1419 return (curord<<8)|currow;
1420 }
1421
xmpSetPos(int ord,int row)1422 void __attribute__ ((visibility ("internal"))) xmpSetPos(int ord, int row)
1423 {
1424 int i;
1425
1426 if (row<0)
1427 ord--;
1428 if (ord>=nord)
1429 ord=0;
1430 if (ord<0)
1431 {
1432 ord=0;
1433 row=0;
1434 }
1435 if (row>=patlens[orders[ord]])
1436 {
1437 ord++;
1438 row=0;
1439 }
1440 if (ord>=nord)
1441 ord=0;
1442 if (row<0)
1443 {
1444 row+=patlens[orders[ord]];
1445 if (row<0)
1446 row=0;
1447 }
1448 for (i=0; i<nchan; i++)
1449 mcpSet(i, mcpCReset, 0);
1450 jumptoord=ord;
1451 jumptorow=row;
1452 curtick=curtempo;
1453 curord=ord;
1454 currow=row;
1455 usersetpos=1;
1456 querpos=0;
1457 quewpos=0;
1458 realpos=(curord<<16)|(currow<<8);
1459 }
1460
xmpGetLChanSample(unsigned int ch,int16_t * b,unsigned int len,uint32_t rate,int opt)1461 int __attribute__ ((visibility ("internal"))) xmpGetLChanSample(unsigned int ch, int16_t *b, unsigned int len, uint32_t rate, int opt)
1462 {
1463 return mcpGetChanSample(ch, b, len, rate, opt);
1464 }
1465
xmpMute(int i,int m)1466 void __attribute__ ((visibility ("internal"))) xmpMute(int i, int m)
1467 {
1468 mutech[i]=m;
1469 }
1470
xmpLoop(void)1471 int __attribute__ ((visibility ("internal"))) xmpLoop(void)
1472 {
1473 return looped;
1474 }
1475
xmpSetLoop(int x)1476 void __attribute__ ((visibility ("internal"))) xmpSetLoop(int x)
1477 {
1478 looping=x;
1479 }
1480
xmpLoadSamples(struct xmodule * m)1481 int __attribute__ ((visibility ("internal"))) xmpLoadSamples(struct xmodule *m)
1482 {
1483 return mcpLoadSamples(m->sampleinfos, m->nsampi);
1484 }
1485
xmpPlayModule(struct xmodule * m,struct ocpfilehandle_t * file)1486 int __attribute__ ((visibility ("internal"))) xmpPlayModule(struct xmodule *m, struct ocpfilehandle_t *file)
1487 {
1488 int i;
1489
1490 memset(channels, 0, sizeof(channels));
1491
1492 looping=1;
1493 globalvol=0x40;
1494 realgvol=0x40;
1495 jumptorow=0;
1496 jumptoord=0;
1497 curord=0;
1498 currow=0;
1499 realpos=0;
1500 ninst=m->ninst;
1501 nord=m->nord;
1502 nsamp=m->nsamp;
1503 instruments=m->instruments;
1504 envelopes=m->envelopes;
1505 samples=m->samples;
1506 sampleinfos=m->sampleinfos;
1507 patterns=m->patterns;
1508 orders=m->orders;
1509 patlens=m->patlens;
1510 linearfreq=m->linearfreq;
1511 nchan=m->nchan;
1512 loopord=m->loopord;
1513 nenv=m->nenv;
1514 ismod=m->ismod;
1515 ft2_e60bug=m->ft2_e60bug;
1516 looped=0;
1517
1518 curtempo=m->initempo;
1519 curtick=m->initempo-1;
1520
1521 for (i=0; i<nchan; i++)
1522 {
1523 channels[i].chPan=m->panpos[i];
1524 mutech[i]=0;
1525 }
1526
1527 quelen=100;
1528 que=malloc(sizeof(int)*quelen*4);
1529 if (!que)
1530 return 0;
1531 querpos=0;
1532 quewpos=0;
1533
1534 curbpm=m->inibpm;
1535 realtempo=m->inibpm;
1536 realspeed=m->initempo;
1537 firstspeed=256*2*curbpm/5;
1538 if (!mcpOpenPlayer(nchan, xmpPlayTick, file))
1539 return 0;
1540
1541 if (nchan!=mcpNChan)
1542 {
1543 mcpClosePlayer();
1544 return 0;
1545 }
1546
1547 return 1;
1548 }
1549
xmpStopModule(void)1550 void __attribute__ ((visibility ("internal"))) xmpStopModule(void)
1551 {
1552 mcpClosePlayer();
1553 free(que);
1554 }
1555
xmpGetGlobInfo(int * tmp,int * bpm,int * gvol)1556 void __attribute__ ((visibility ("internal"))) xmpGetGlobInfo(int *tmp, int *bpm, int *gvol)
1557 {
1558 *tmp=realspeed;
1559 *bpm=realtempo;
1560 *gvol=realgvol;
1561 }
1562
1563 /*
1564 int __attribute__ ((visibility ("internal"))) xmpGetTime(void)
1565 {
1566 return mcpGet(-1, mcpGTimer);
1567 }*/
1568
1569 /*int __attribute__ ((visibility ("internal"))) xmpGetSync(int ch, int *time)
1570 {
1571 ReadQue();
1572 if ((ch<0)||(ch>=nchan))
1573 {
1574 *time=xmpGetTime()-realsynctime;
1575 return realsync;
1576 } else {
1577 *time=xmpGetTime()-channels[ch].chSyncTime;
1578 return channels[ch].chSync;
1579 }
1580 }*/
1581
1582 /*int __attribute__ ((visibility ("internal"))) xmpGetTickTime(void)
1583 {
1584 ReadQue();
1585 return 65536*5/(2*realtempo);
1586 }*/
1587
1588 /*int __attribute__ ((visibility ("internal"))) xmpGetRowTime(void)
1589 {
1590 ReadQue();
1591 return 65536*5*realspeed/(2*realtempo);
1592 }*/
1593
1594 /*void __attribute__ ((visibility ("internal"))) xmpSetEvPos(int ch, int pos, int modtype, int mod)
1595 {
1596 struct channel *c;
1597 if ((ch<0)||(ch>=nchan))
1598 return;
1599 c=&channels[ch];
1600 c->evpos0=pos;
1601 c->evmodtype=modtype;
1602 c->evmod=mod;
1603 c->evmodpos=0;
1604 c->evpos=-1;
1605 c->evtime=-1;
1606 }*/
1607
1608 /*int __attribute__ ((visibility ("internal"))) xmpGetEvPos(int ch, int *time)
1609 {
1610 ReadQue();
1611 if ((ch<0)||(ch>=nchan))
1612 {
1613 *time=-1;
1614 return -1;
1615 }
1616 *time=xmpGetTime()-channels[ch].evtime;
1617 return channels[ch].evpos;
1618 }*/
1619
1620 /*int __attribute__ ((visibility ("internal"))) xmpFindEvPos(int pos, int *time)
1621 {
1622 int i;
1623 ReadQue();
1624 for (i=0; i<nchan; i++)
1625 if (channels[i].evpos==pos)
1626 break;
1627 *time=xmpGetTime()-channels[i].evtime;
1628 return channels[i].evpos;
1629 }*/
1630
xmpGetChanInfo(unsigned char ch,struct xmpchaninfo * ci)1631 void __attribute__ ((visibility ("internal"))) xmpGetChanInfo(unsigned char ch, struct xmpchaninfo *ci)
1632 {
1633 const struct channel *t=&channels[ch];
1634 ci->note=t->curnote+11;
1635 ci->vol=t->chVol;
1636 if (!t->chFadeVol)
1637 ci->vol=0;
1638 ci->pan=t->chPan;
1639 ci->notehit=t->notehit;
1640 ci->volslide=t->volslide;
1641 ci->pitchslide=t->pitchslide;
1642 ci->panslide=t->panslide;
1643 ci->volfx=t->volfx;
1644 ci->pitchfx=t->pitchfx;
1645 ci->notefx=t->notefx;
1646 ci->fx=t->fx;
1647 }
1648
xmpGetGlobInfo2(struct xmpglobinfo * gi)1649 void __attribute__ ((visibility ("internal"))) xmpGetGlobInfo2(struct xmpglobinfo *gi)
1650 {
1651 gi->globvol=globalvol;
1652 gi->globvolslide=globalfx;
1653 }
1654