1 /* OpenCP Module Player
2  * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3  *
4  * ITPlayer - player for Impulse Tracker 2.xx modules
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 <kb@nwn.de>
24  *    -fixed many many uncountable small replay bugs
25  *    -strange division by zero on song start fixed (occurred when
26  *     the player irq/timer routine started before it was supposed
27  *     to do so)
28  *    -vastly improved channel allocation (uncontrollably vanishing
29  *     channels should belong to the past)
30  *    -implemented filter handling (not used tho, as the wavetable
31  *     system isn't able to handle them, so it's only for playing
32  *     filtered ITs right (pitch envelopes dont get messed up anymore))
33  *    -implemented exit on song loop function
34  *    -added many many various structures, data types, variables and
35  *     functions for the player's display
36  *    -again fixed even more uncountable replay bugs (a BIG thanx to
37  *     mindbender who didn't only reveal two of them, but made it
38  *     possible that around 5 other bugs suddenly appeared after
39  *     fixing :)
40  *    -finally implemented Amiga frequency table on heavy public
41  *     demand (or better: cut/pasted/modified it from the xm player -
42  *     be happy with this or not)
43  *     (btw: "heavy public demand" == Mindbender again ;))
44  *    -meanwhile, fixed so many replay bugs again that i'd better have
45  *     written this player from scratch ;)
46  *    -rewritten envelope handling (envelope loops weren't correct and
47  *     the routine crashed on some ITs (due to a bug in pulse's saving
48  *     routine i think)
49  *    -fixed replay bugs again (thx to maxx)
50  *    -and again fixed replay bugs (slowly, this is REALLY getting on
51  *     my nerves... grmMRMMRMRMRMROARRMRMrmrararharhhHaheaheaheheaHEAHE)
52  *  -kbwhenever Tammo Hinrichs <opencp@gmx.net>
53  *    -now plays correctly when first order pos contains "+++"
54  *    -vibrato tables fixed (were backwards according to some people)
55  *    -too fast note retrigs fixed
56  *  -ryg990426  Fabian Giesen  <fabian@jdcs.su.nw.schule.de>
57  *    -bla. again applied some SIMPLE bugfix from kb. this sucks :)
58  *  -kb990606 Tammo Hinrichs <opencp@gmx.net>
59  *    -bugfixed instrument filter settings
60  *    -added filter calls to the mcp
61  *  -doj20020901 Dirk Jagdmann <doj@cubic.org>
62  *    -enable/disable pattern looping
63  *  -ss20040908  Stian Skjelstad <stian@nixia.no>
64  *    -copy 5 bytes instead of sizeof(c->delayed) in playtick(). We don't want to touch unmapped memory
65  */
66 
67 
68 /* to do:
69  * - midi command parsing
70  * - filter envelopes still to be tested
71  * - fucking damned division overflow error in wavetable device still
72  *   has to be found (when using wavetable sound cards).
73  *   (fixed due to some zero checks in devwiw/gus/sb32???)
74  */
75 
76 
77 #include "config.h"
78 #include <stdlib.h>
79 #include <string.h>
80 #include "types.h"
81 #include "cpiface/cpiface.h"
82 #include "dev/mcp.h"
83 #include "itplay.h"
84 #include "stuff/imsrtns.h"
85 
86 
87 /* overriding stdlib's one, even though it would do */
88 #define random(this) it_random(this)
89 static int it_random(struct itplayer *this)
90 {
91 	this->randseed=this->randseed*0x15A4E35+12345;
92 	return (this->randseed>>16)&32767;
93 }
94 
95 static struct itplayer *staticthis=NULL;
96 
97 static int8_t sintab[256] =
98 {
99 	  0,   2,   3,   5,   6,   8,   9,  11,  12,  14,  16,  17,  19,  20,
100 	 22,  23,  24,  26,  27,  29,  30,  32,  33,  34,  36,  37,  38,  39,
101 	 41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,
102 	 55,  56,  56,  57,  58,  59,  59,  60,  60,  61,  61,  62,  62,  62,
103 	 63,  63,  63,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,
104 	 63,  63,  63,  62,  62,  62,  61,  61,  60,  60,  59,  59,  58,  57,
105 	 56,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44,
106 	 43,  42,  41,  39,  38,  37,  36,  34,  33,  32,  30,  29,  27,  26,
107 	 24,  23,  22,  20,  19,  17,  16,  14,  12,  11,   9,   8,   6,   5,
108 	  3,   2,   0,  -2,  -3,  -5,  -6,  -8,  -9, -11, -12, -14, -16, -17,
109 	-19, -20, -22, -23, -24, -26, -27, -29, -30, -32, -33, -34, -36, -37,
110 	-38, -39, -41, -42, -43, -44, -45, -46, -47, -48, -49, -50, -51, -52,
111 	-53, -54, -55, -56, -56, -57, -58, -59, -59, -60, -60, -61, -61, -62,
112 	-62, -62, -63, -63, -63, -64, -64, -64, -64, -64, -64, -64, -64, -64,
113 	-64, -64, -63, -63, -63, -62, -62, -62, -61, -61, -60, -60, -59, -59,
114 	-58, -57, -56, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46,
115 	-45, -44, -43, -42, -41, -39, -38, -37, -36, -34, -33, -32, -30, -29,
116 	-27, -26, -24, -23, -22, -20, -19, -17, -16, -14, -12, -11,  -9,  -8,
117 	 -6,  -5,  -3,  -2
118 };
119 
120 
121 static void playtick(struct itplayer *this);
122 static int range64(int v);
123 static int range128(int v);
124 static void dovibrato(struct itplayer *this, struct it_logchan *c);
125 static void putque(struct itplayer *this, int type, int val1, int val2);
126 static void readque(struct itplayer *this);
127 static void dotremolo(struct itplayer *this, struct it_logchan *c);
128 static void dodelay(struct itplayer *this, struct it_logchan *c);
129 static void dopanbrello(struct itplayer *this, struct it_logchan *c);
130 
131 
132 static void playtickstatic(void)
133 {
134 	playtick(staticthis);
135 }
136 
137 static void playnote(struct itplayer *this, struct it_logchan *c, const uint8_t *cmd)
138 {
139 	int instchange=0;
140 	/* int triginst=0;  unused */
141 	int porta, frq;
142 	struct it_physchan *p;
143 	const struct it_sample *s;
144 	const struct it_instrument *in;
145 
146 	if (cmd[0])
147 	{
148 		c->lastnote=cmd[0];
149 		/* this is kind of wierd, but we need to know of retrigger changes already now */
150 		if (cmd[3]==cmdRetrigger)
151 			c->retrigpos=cmd[4]>>4|!(cmd[4]&0xf0); /* |!(cmd[4]&0xf0) makes value 0, into 1 */
152 		else
153 			c->retrigpos=c->retrigspd;
154 	}
155 
156 	if (cmd[1])
157 	{
158 		if (cmd[1]!=c->lastins)
159 			instchange=1;
160 		c->lastins=cmd[1];
161 	}
162 
163 	if (c->lastnote==cmdNNoteOff)
164 	{
165 		if (c->pch)
166 			c->pch->noteoff=1;
167 		return;
168 	}
169 	if (c->lastnote==cmdNNoteCut)
170 	{
171 		if (c->pch)
172 			c->pch->notecut=1;
173 		return;
174 	}
175 	if (c->lastnote>=cmdNNoteFade)
176 	{
177 		if (c->pch)
178 			c->pch->notefade=1;
179 		return;
180 	}
181 	if ((c->lastins>this->ninst)||!c->lastins||!c->lastnote||(c->lastnote>=cmdNNoteFade))
182 		return;
183 
184 	c->curnote=c->lastnote;
185 
186 	porta=(cmd[3]==cmdPortaNote)||(cmd[3]==cmdPortaVol)||((cmd[2]>=cmdVPortaNote)&&(cmd[2]<(cmdVPortaNote+10)));
187 
188 	if (!c->pch || c->pch->dead || !c->pch->fadeval)
189 		porta=0;
190 
191 	if (instchange || !porta)
192 		c->fnotehit=1;
193 
194 	do
195 	{
196 		if (!((!cmd[0]) && cmd[1] && (!instchange) && (!porta) && (cmd[3]!=cmdOffset) && c->pch))
197 			break;
198 
199 /* http://eval.sovietrussia.org/wiki/Player_abuse_tests#Ping-pong_loop_and_sample_number
200  *
201  * Bug-fix workaround for cases where you just set instrument number with no note, should not re-trigger note,
202  * just reset volumes
203  */
204 		if (!(p=c->pch))
205 			break;
206 		if (p->notecut)
207 			break;
208 		if (p->dead)
209 			break;
210 		if (!(s=p->smp))
211 			break;
212 		if (!(in=p->inst))
213 			break;
214 		c->nna=in->nna;
215 		c->vol=((100-in->rv)*s->vol+in->rv*(rand()%65))/100;
216 		c->fvol=c->vol;
217 		c->pan=(in->dfp&128)?c->cpan:in->dfp;
218 		c->pan=(s->dfp&128)?(s->dfp&127):c->pan;
219 		c->pan=range64(c->pan+(((c->lastnote-cmdNNote-in->ppc)*in->pps)>>8));
220 		c->pan=/*(in->dfp&128)?c->pan:*/range64(c->pan+((in->rp*(rand() %129 -64))>>6));
221 		c->fpan=c->pan;
222 		return;
223 	} while(0); /* runs atleast one time */
224 
225 	if (c->fnotehit)
226 	{
227 		int smp;
228 
229 		if (porta)
230 			c->pch->notecut=1;
231 		smp=this->instruments[c->lastins-1].keytab[c->lastnote-cmdNNote][1];
232 		if (!smp||(smp>this->nsamp))
233 			return;
234 		if (!porta)
235 		{
236 			if (c->pch)
237 			{
238 				c->newchan.volenvpos=c->pch->volenvpos;
239 				c->newchan.panenvpos=c->pch->panenvpos;
240 				c->newchan.pitchenvpos=c->pch->pitchenvpos;
241 				c->newchan.filterenvpos=c->pch->filterenvpos;
242 				c->newchan=*c->pch;
243 				switch (c->nna)
244 				{
245 					case 0: c->pch->notecut=1; break;
246 					case 2: c->pch->noteoff=1; break;
247 					case 3: c->pch->notefade=1; break;
248 				}
249 				c->pch=0;
250 			} else {
251 				c->newchan.volenvpos=0;
252 				c->newchan.panenvpos=0;
253 				c->newchan.pitchenvpos=0;
254 				c->newchan.filterenvpos=0;
255 			}
256 			c->pch=&c->newchan;
257 			c->pch->avibpos=0;
258 			c->pch->avibdep=0;
259 			/* c->retrigpos=0; */
260 		}
261 		if (this->samples[smp-1].handle==0xFFFF)
262 		{
263 			fprintf(stderr, "playit/itplay.c: Assert #1\n");
264 			c->pch=0; /* deallocate channel, invalid sample */
265 			return;
266 		}
267 
268 		c->pch->inst=&this->instruments[c->lastins-1];
269 		if (!c->pch->inst)
270 		{
271 			/* should be unreachable */
272 			fprintf(stderr, "playit/itplay.c: Assert #2\n");
273 			c->pch=0;
274 		}
275 		c->pch->smp=&this->samples[smp-1];
276 		if (!c->pch->smp)
277 		{
278 			/* should be unreachable */
279 			fprintf(stderr, "playit/itplay.c: Assert #3\n");
280 			c->pch=0;
281 		}
282 		c->basenote=c->pch->note=c->lastnote-cmdNNote;
283 		c->realnote=c->pch->inst->keytab[c->basenote][0];
284 		c->pch->noteoffset=(60-c->realnote+c->basenote)*256+c->pch->smp->normnote;
285 	}
286 
287 	p=c->pch;
288 	s=p->smp;
289 	in=p->inst;
290 
291 	if (cmd[3]==cmdOffset)
292 	{
293 		if (cmd[4])
294 			c->offset=(c->offset&0xF00)|cmd[4];
295 		p->newsamp=s->handle;
296 		p->newpos=c->offset<<8;
297 		if (p->newpos>=(signed)this->sampleinfos[s->handle].length)
298 			p->newpos=this->sampleinfos[s->handle].length-16;
299 	} else if (c->fnotehit)
300 	{
301 		p->newsamp=s->handle;
302 		p->newpos=0;
303 	}
304 
305 	if (c->fnotehit || cmd[1])
306 	{
307 		int i;
308 
309 		if (in->dct)
310 		{
311 			for (i=0; i<this->npchan; i++)
312 			{
313 				struct it_physchan *dp=&this->pchannels[i];
314 				if (dp==p)
315 					continue;
316 				if (dp->lch!=p->lch)
317 					continue;
318 				if (dp->inst!=p->inst)
319 					continue;
320 				if ((in->dct!=3)&&(dp->smp!=p->smp))
321 					continue;
322 				if ((in->dct==1)&&(dp->note!=p->note))
323 					continue;
324 				switch (in->dca)
325 				{
326 					case 0: dp->notecut=1; break;
327 					case 1: dp->noteoff=1; break;
328 					case 2: dp->notefade=1; break;
329 				}
330 			}
331 		}
332 
333 		if (cmd[1])
334 		{
335 			p->fadeval=1024;
336 			p->fadespd=in->fadeout;
337 			p->notefade=0;
338 			p->dead=0;
339 			p->notecut=0;
340 			p->noteoff=0;
341 			p->looptype=0;
342 			p->volenv=in->envs[0].type&env_type_active;
343 			p->panenv=in->envs[1].type&env_type_active;
344 			p->penvtype=(in->envs[2].type&env_type_filter);
345 			p->pitchenv=(in->envs[2].type&env_type_active) && !p->penvtype;
346 			p->filterenv=(in->envs[2].type&env_type_active) && p->penvtype;
347 			if (!(in->envs[0].type&env_type_carry))
348 				p->volenvpos=0;
349 			if (!(in->envs[1].type&env_type_carry))
350 				p->panenvpos=0;
351 			if (!(in->envs[2].type&env_type_carry))
352 			{
353 				p->pitchenvpos=0;
354 				p->filterenvpos=0;
355 			}
356 
357 			c->nna=in->nna;
358 			c->vol=((100-in->rv)*s->vol+in->rv*(rand()%65))/100;
359 			c->fvol=c->vol;
360 			c->pan=(in->dfp&128)?c->cpan:in->dfp;
361 			c->pan=(s->dfp&128)?(s->dfp&127):c->pan;
362 			c->pan=range64(c->pan+(((c->lastnote-cmdNNote-in->ppc)*in->pps)>>8));
363 			c->pan=/*(in->dfp&128)?c->pan:*/range64(c->pan+((in->rp*(rand() %129 -64))>>6));
364 			c->fpan=c->pan;
365 			c->cutoff=(in->ifp&128)?in->ifp:c->cutoff;
366 			c->fcutoff=c->cutoff;
367 			c->reso=(in->ifr&128)?in->ifr:c->reso;
368 		}
369 	}
370 
371 	if (porta && instchange && !this->geffect)
372 	{
373 		c->basenote=c->lastnote-cmdNNote;
374 		c->realnote=in->keytab[c->basenote][0];
375 		p->noteoffset=(60-c->realnote+c->basenote)*256+s->normnote;
376 	}
377 
378 	frq=p->noteoffset-256*(c->lastnote-cmdNNote);
379 	if (!this->linear)
380 		frq=mcpGetFreq6848(frq);
381 	c->dpitch=frq;
382 	if (!porta)
383 		c->fpitch=c->pitch=c->dpitch;
384 }
385 
386 static void playvcmd(struct itplayer *this, struct it_logchan *c, int vcmd)
387 {
388 	c->vcmd=vcmd;
389 	if ((vcmd>=cmdVVolume)&&(vcmd<=(cmdVVolume+64)))
390 		c->fvol=c->vol=vcmd-cmdVVolume;
391 	else if ((vcmd>=cmdVPanning)&&(vcmd<=(cmdVPanning+64)))
392 	{
393 		c->fpan=c->pan=c->cpan=vcmd-cmdVPanning;
394 		c->srnd=0;
395 	} else if ((vcmd>=cmdVFVolSlU)&&(vcmd<(cmdVFVolSlU+10)))
396 	{
397 		if (vcmd!=cmdVFVolSlU)
398 			c->vvolslide=vcmd-cmdVFVolSlU;
399 		c->fvol=c->vol=range64(c->vol+c->vvolslide);
400 	} else if ((vcmd>=cmdVFVolSlD)&&(vcmd<(cmdVFVolSlD+10)))
401 	{
402 		if (vcmd!=cmdVFVolSlD)
403 			c->vvolslide=vcmd-cmdVFVolSlD;
404 		c->fvol=c->vol=range64(c->vol-c->vvolslide);
405 	} else if ((vcmd>=cmdVVolSlU)&&(vcmd<(cmdVVolSlU+10)))
406 	{
407 		if (vcmd!=cmdVVolSlU)
408 			c->vvolslide=vcmd-cmdVVolSlU;
409 		c->fvolslide=ifxVSUp;
410 	} else if ((vcmd>=cmdVVolSlD)&&(vcmd<(cmdVVolSlD+10)))
411 	{
412 		if (vcmd!=cmdVVolSlD)
413 			c->vvolslide=vcmd-cmdVVolSlD;
414 		c->fvolslide=ifxVSDown;
415 	} else  if ((vcmd>=cmdVPortaD)&&(vcmd<(cmdVPortaD+10)))
416 	{
417 		if (vcmd!=cmdVPortaD)
418 			c->porta=4*(vcmd-cmdVPortaD);
419 		c->vporta=c->porta;
420 		c->fpitchslide=ifxPSDown;
421 	} else if ((vcmd>=cmdVPortaU)&&(vcmd<(cmdVPortaU+10)))
422 	{
423 		if (vcmd!=cmdVPortaU)
424 			c->porta=4*(vcmd-cmdVPortaU);
425 		c->vporta=c->porta;
426 		c->fpitchslide=ifxPSUp;
427 	} else if ((vcmd>=cmdVPortaNote)&&(vcmd<(cmdVPortaNote+10)))
428 	{
429 		if (vcmd!=cmdVPortaNote)
430 		{
431 			int tmp="\x00\x01\x04\x08\x10\x20\x40\x60\x80\xFF"[vcmd-cmdVPortaNote];
432 			if (this->geffect)
433 				c->portanote=tmp;
434 			else
435 				c->porta=tmp;
436 		}
437 		if (this->geffect)
438 			c->vportanote=c->portanote;
439 		else
440 			c->vporta=c->porta;
441 
442 		c->fpitchslide=ifxPSToNote;
443 	} else if ((vcmd>=cmdVVibrato)&&(vcmd<(cmdVVibrato+10)))
444 	{
445 		if (vcmd!=cmdVVibrato)
446 			c->vibdep=(vcmd-cmdVVibrato)*(this->oldfx?8:4);
447 		c->fpitchfx=ifxPXVibrato;
448 		dovibrato(this, c);
449 	}
450 }
451 
452 static int range64(int v)
453 {
454 	return (v<0)?0:(v>64)?64:v;
455 }
456 
457 static int range128(int v)
458 {
459 	return (v<0)?0:(v>128)?128:v;
460 }
461 
462 static int rowslide(int data)
463 {
464 	if ((data&0x0F)==0x0F)
465 		return data>>4;
466 	else
467 		if ((data&0xF0)==0xF0)
468 			return -(data&0xF);
469 	return 0;
470 }
471 
472 static int rowudslide(int data)
473 {
474 	if (data>=0xF0)
475 		return (data&0xF)*4;
476 	else if (data>=0xE0)
477 		return (data&0xF);
478 	return 0;
479 }
480 
481 static int rowvolslide(int data)
482 {
483 	if (data==0xF0)
484 		return 0xF;
485 	else
486 		if (data==0x0F)
487 			return -0xF;
488 		else
489 			return rowslide(data);
490 }
491 
492 static int tickslide(int data)
493 {
494 	if (!(data&0x0F))
495 		return data>>4;
496 	else
497 		if (!(data&0xF0))
498 			return -(data&0xF);
499 	return 0;
500 }
501 
502 static void doretrigger(struct it_logchan *c)
503 {
504 	int x;
505 	struct it_physchan *p;
506 
507 	c->retrigpos--;
508 	if (c->retrigpos)
509 		return;
510 	c->retrigpos=c->retrigspd;
511 	x=c->vol;
512 	switch (c->retrigvol)
513 	{
514 		case 1: case 2: case 3: case 4: case 5: x-=1<<(c->retrigvol-1); break;
515 		case 6: x=(5*x)>>3; break;
516 		case 7: x=x>>1; break;
517 		case 9: case 10: case 11: case 12: case 13: x+=1<<(c->retrigvol-9); break;
518 		case 14: x=(3*x)>>1; break;
519 		case 15: x=2*x; break;
520 	}
521 	c->fvol=c->vol=range64(x);
522 	if (!c->pch)
523 		return;
524 	p=c->pch;
525 	p->newpos=0;
526 	p->dead=0;
527 }
528 
529 static void dotremor(struct it_logchan *c)
530 {
531 	if (c->tremoroncounter)
532 		c->tremoroncounter--;
533 	if (!c->tremoroncounter)
534 	{
535 		if (c->tremoroffcounter)
536 		{
537 			c->fvol=0;
538 			c->tremoroffcounter--;
539 		} else {
540 			c->tremoroncounter=c->tremoron;
541 			c->tremoroffcounter=c->tremoroff;
542 		}
543 	}
544 }
545 
546 static int ishex(uint8_t c)
547 {
548 	return ((c>=48 && c<58) || (c>=65 && c<71));
549 }
550 
551 
552 static void parsemidicmd(struct it_logchan *c, char *cmd, int z)
553 {
554 	uint8_t bytes[32];
555 	int  count=0;
556 	while (*cmd)
557 	{
558 		if (ishex(*cmd))
559 		{
560 			int v0=(*cmd)-48;
561 			if (v0>9) v0-=7;
562 			cmd++;
563 			if (ishex(*cmd))
564 			{
565 				int v1=(*cmd)-48;
566 				if (v1>9) v1-=7;
567 				cmd++;
568 				bytes[count++]=(v0<<4)|v1;
569 			}
570 		} else if ((*cmd)=='Z')
571 		{
572 			bytes[count++]=z;
573 			cmd++;
574 		} else
575 			cmd++;
576 	}
577 	/* filter commands? */
578 	if (count==4 && bytes[0]==0xf0 && bytes[1]==0xf0)
579 	{
580 		switch (bytes[2])
581 		{
582 			case 0:
583 				c->cutoff=c->fcutoff=bytes[3]+128;
584 				break;
585 			case 1:
586 				c->reso=bytes[3]+128;
587 				break;
588 		}
589 	}
590 }
591 
592 static void playcmd(struct itplayer *this, struct it_logchan *c, int cmd, int data)
593 {
594 	int i;
595 	c->command=cmd;
596 	switch (cmd)
597 	{
598 		case cmdSpeed:
599 			if (data)
600 				this->speed=data;
601 			putque(this, queSpeed, -1, this->speed);
602 			break;
603 		case cmdJump:
604 			this->gotorow=0;
605 			this->gotoord=data;
606 			break;
607 		case cmdBreak:
608 			if (this->gotoord==-1)
609 				this->gotoord=this->curord+1;
610 			this->gotorow=data;
611 			break;
612 		case cmdVolSlide:
613 			if (data)
614 				c->volslide=data;
615 			data=c->volslide;
616 			if (!(data&0x0F) && (data&0xF0))
617 			{
618 				c->fvolslide=ifxVSUp;
619 				c->fx=ifxVolSlideUp;
620 			} else if (!(data&0xF0) && (data&0x0F))
621 			{
622 				c->fvolslide=ifxVSDown;
623 				c->fx=ifxVolSlideDown;
624 			} else if ((data&0x0F)>0x0D && (data&0xF0))
625 				c->fx=ifxRowVolSlideUp;
626 			else if (((data&0xF0)>0xD0) && (data&0x0F))
627 				c->fx=ifxRowVolSlideDown;
628 			c->fvol=c->vol=range64(c->vol+rowvolslide(c->volslide));
629 			break;
630 		case cmdPortaD:
631 			if (data)
632 				c->porta=data;
633 			c->eporta=c->porta;
634 			c->fpitchslide=ifxPSDown;
635 			c->fx=ifxPitchSlideDown;
636 			c->fpitch=c->pitch=c->pitch+4*rowudslide(c->eporta);
637 			break;
638 		case cmdPortaU:
639 			if (data)
640 				c->porta=data;
641 			c->eporta=c->porta;
642 			c->fpitchslide=ifxPSUp;
643 			c->fx=ifxPitchSlideUp;
644 			c->fpitch=c->pitch=c->pitch-4*rowudslide(c->eporta);
645 			break;
646 		case cmdPortaNote:
647 			if (data)
648 			{
649 				if (this->geffect)
650 					c->portanote=data;
651 				else
652 					c->porta=data;
653 			}
654 			if (this->geffect)
655 				c->eportanote=c->portanote;
656 			else
657 				c->eporta=c->porta;
658 			c->fpitchslide=ifxPSToNote;
659 			c->fx=ifxPitchSlideToNote;
660 			break;
661 		case cmdVibrato:
662 			if (data&0xF)
663 				c->vibdep=(data&0xF)*(this->oldfx?8:4);
664 			if (data>>4)
665 				c->vibspd=data>>4;
666 			c->fpitchfx=ifxPXVibrato;
667 			c->fx=ifxPitchVibrato;
668 			dovibrato(this, c);
669 			break;
670 		case cmdTremor:
671 			if (data)
672 			{
673 				c->tremoron=(data>>4)+(this->oldfx);
674 				c->tremoroff=(data&0xF)+(this->oldfx);
675 			}
676 			if (!c->tremoroff)
677 				c->tremoroff=1;
678 			if (!c->tremoron)
679 				c->tremoron=1;
680 			c->fvolfx=ifxVXTremor;
681 			c->fx=ifxTremor;
682 			dotremor(c);
683 			break;
684 		case cmdArpeggio:
685 			if (data)
686 			{
687 				c->arpeggio1=data>>4;
688 				c->arpeggio2=data&0xF;
689 			}
690 			c->fpitchfx=ifxPXArpeggio;
691 			c->fx=ifxArpeggio;
692 			break;
693 		case cmdPortaVol:
694 			if (data)
695 				c->volslide=data;
696 			data=c->volslide;
697 			c->fpitchslide=ifxPSToNote;
698 			c->fx=ifxPitchSlideToNote;
699 			if (!(data&0x0F) && (data&0xF0))
700 			{
701 				c->fvolslide=ifxVSUp;
702 				c->fx=ifxVolSlideUp;
703 			} else if (!(data&0xF0) && (data&0x0F))
704 			{
705 				c->fvolslide=ifxVSDown;
706 				c->fx=ifxVolSlideDown;
707 			} else if ((data&0x0F)>0x0D && (data&0xF0))
708 				c->fx=ifxRowVolSlideUp;
709 			else if (((data&0xF0)>0xD0) && (data&0x0F))
710 				c->fx=ifxRowVolSlideDown;
711 			c->fvol=c->vol=range64(c->vol+rowvolslide(c->volslide));
712 			break;
713 		case cmdVibVol:
714 			if (data)
715 				c->volslide=data;
716 			data=c->volslide;
717 			c->fpitchfx=ifxPXVibrato;
718 			c->fx=ifxPitchVibrato;
719 			if (!(data&0x0F) && (data&0xF0))
720 			{
721 				c->fvolslide=ifxVSUp;
722 				c->fx=ifxVolSlideUp;
723 			} else if (!(data&0xF0) && (data&0x0F))
724 			{
725 				c->fvolslide=ifxVSDown;
726 				c->fx=ifxVolSlideDown;
727 			} else if ((data&0x0F)>0x0D && (data&0xF0))
728 				c->fx=ifxRowVolSlideUp;
729 			else if (((data&0xF0)>0xD0) && (data&0x0F))
730 				c->fx=ifxRowVolSlideDown;
731 			c->fvol=c->vol=range64(c->vol+rowvolslide(c->volslide));
732 			dovibrato(this, c);
733 			break;
734 		case cmdChanVol:
735 			if (data<=64)
736 				c->cvol=data;
737 			break;
738 		case cmdChanVolSlide:
739 			if (data)
740 				c->cvolslide=data;
741 			data=c->cvolslide;
742 			if ((data&0x0F)==0 && data&0xF0)
743 				c->fx=ifxChanVolSlideUp;
744 			else if ((data&0xF0)==0 && data&0x0F)
745 				c->fx=ifxChanVolSlideDown;
746 			else if ((data&0x0F)>0x0D && data&0xF0)
747 				c->fx=ifxRowChanVolSlideUp;
748 			else if ((data&0xF0)>0xD0 && data&0x0F)
749 				c->fx=ifxRowChanVolSlideDown;
750 			c->cvol=range64(c->cvol+rowslide(c->cvolslide));
751 			break;
752 		case cmdOffset:
753 			c->fx=ifxOffset;
754 			break;
755 		case cmdPanSlide:
756 			if (data)
757 				c->panslide=data;
758 			data=c->panslide;
759 			if (!(data&0x0F))
760 			{
761 				c->fpanslide=ifxPnSLeft;
762 				c->fx=ifxPanSlideLeft;
763 			} else if (!(data&0xF0))
764 			{
765 				c->fpanslide=ifxPnSRight;
766 				c->fx=ifxPanSlideRight;
767 			}
768 			c->fpan=c->cpan=c->pan=range64(c->pan-rowslide(c->panslide));
769 			break;
770 		case cmdRetrigger:
771 			if (data)
772 			{
773 				c->retrigspd=data&0xF;
774 				c->retrigvol=data>>4;
775 			}
776 			if (!c->retrigspd)
777 				c->retrigspd=1;
778 			c->fx=ifxRetrig;
779 			doretrigger(c);
780 			break;
781 		case cmdTremolo:
782 			if (data&0xF)
783 				c->tremdep=data&0xF;
784 			if (data>>4)
785 				c->tremspd=data>>4;
786 			c->fvolfx=ifxVXVibrato;
787 			c->fx=ifxVolVibrato;
788 			dotremolo(this, c);
789 			break;
790 		case cmdSpecial:
791 			switch (c->specialcmd)
792 			{
793 				case cmdSVibType:
794 					if (c->specialdata<4)
795 						c->vibtype=c->specialdata;
796 					break;
797 				case cmdSTremType:
798 					if (c->specialdata<4)
799 						c->tremtype=c->specialdata;
800 					break;
801 				case cmdSPanbrType:
802 					if (c->specialdata<4)
803 						c->panbrtype=c->specialdata;
804 					break;
805 				case cmdSPatDelayTick:
806 					this->patdelaytick=c->specialdata;
807 					break;
808 				case cmdSInstFX:
809 					switch (c->specialdata)
810 					{
811 						case cmdSIPastCut:
812 							c->fx=ifxPastCut;
813 							for (i=0; i<this->npchan; i++)
814 								if ((c==this->pchannels[i].lchp)&&(c->pch!=&this->pchannels[i]))
815 									this->pchannels[i].notecut=1;
816 							break;
817 						case cmdSIPastOff:
818 							c->fx=ifxPastOff;
819 							for (i=0; i<this->npchan; i++)
820 								if ((c==this->pchannels[i].lchp)&&(c->pch!=&this->pchannels[i]))
821 									this->pchannels[i].noteoff=1;
822 							break;
823 						case cmdSIPastFade:
824 							c->fx=ifxPastFade;
825 							for (i=0; i<this->npchan; i++)
826 								if ((c==this->pchannels[i].lchp)&&(c->pch!=&this->pchannels[i]))
827 									this->pchannels[i].notefade=1;
828 							break;
829 						case cmdSINNACut:
830 							c->nna=0;
831 							break;
832 						case cmdSINNACont:
833 							c->nna=1;
834 							break;
835 						case cmdSINNAOff:
836 							c->nna=2;
837 							break;
838 						case cmdSINNAFade:
839 							c->nna=3;
840 							break;
841 						case cmdSIVolEnvOff:
842 							c->fx=ifxVEnvOff;
843 							if (c->pch)
844 								c->pch->volenv=0;
845 							break;
846 						case cmdSIVolEnvOn:
847 							c->fx=ifxVEnvOn;
848 							if (c->pch)
849 								c->pch->volenv=1;
850 							break;
851 						case cmdSIPanEnvOff:
852 							c->fx=ifxPEnvOff;
853 							if (c->pch)
854 								c->pch->panenv=0;
855 							break;
856 						case cmdSIPanEnvOn:
857 							c->fx=ifxPEnvOn;
858 							if (c->pch)
859 								c->pch->panenv=1;
860 							break;
861 						case cmdSIPitchEnvOff:
862 							c->fx=ifxFEnvOff;
863 							if (c->pch)
864 							{
865 								if (c->pch->penvtype)
866 									c->pch->filterenv=0;
867 								else
868 									c->pch->pitchenv=0;
869 							}
870 							break;
871 						case cmdSIPitchEnvOn:
872 							c->fx=ifxFEnvOn;
873 							if (c->pch)
874 							{
875 								if (c->pch->penvtype)
876 									c->pch->filterenv=1;
877 								else
878 									c->pch->pitchenv=1;
879 							}
880 							break;
881 					}
882 					break;
883 				case cmdSPanning:
884 					c->srnd=0;
885 					c->fpan=c->pan=c->cpan=((c->specialdata*0x11)+1)>>2;
886 					break;
887 				case cmdSSurround:
888 					if (c->specialdata==1)
889 						c->srnd=1;
890 					break;
891 				case cmdSOffsetHigh:
892 					c->offset=(c->offset&0xFF)|(c->specialdata<<8);
893 					break;
894 				case cmdSPatLoop:
895 					/*if(plLoopPatterns)*/ /* TODO */
896 					{
897 						if (!c->specialdata)
898 							c->patloopstart=this->currow;
899 						else
900 						{
901 							if (!c->patloopcount)
902 								c->patloopcount=c->specialdata;
903 							else
904 								c->patloopcount--;
905 							if (c->patloopcount)
906 							{
907 								this->gotorow=c->patloopstart;
908 								this->gotoord=this->curord;
909 							} else {
910 								c->patloopstart=this->currow+1;
911 							}
912 						}
913 					}
914 					break;
915 				case cmdSNoteCut:
916 					c->fx=ifxNoteCut;
917 					if (!c->specialdata)
918 						c->specialdata++; /* SC0 should do the same as SC1 */
919 					break;
920 				case cmdSNoteDelay:
921 					c->fx=ifxDelay;
922 					if (!c->specialdata)
923 						c->specialdata++; /* SD0 should do the same as SD1 */
924 					dodelay(this, c);
925 					break;
926 				case cmdSPatDelayRow:
927 					if (!this->patdelayrow) /* only use the first command, per row */
928 						this->patdelayrow=c->specialdata+1;
929 					break;
930 				case cmdSSetMIDIMacro:
931 					c->sfznum=c->specialdata;
932 					break;
933 			}
934 			break;
935 		case cmdTempo:
936 			if (data)
937 				c->tempo=data;
938 			if (c->tempo>=0x20)
939 			{
940 				this->tempo=c->tempo;
941 				putque(this, queTempo, -1, this->tempo);
942 			}
943 			break;
944 		case cmdFineVib:
945 			if (data&0xF)
946 				c->vibdep=(data&0xF<<(this->oldfx))>>1;
947 			if (data>>4)
948 				c->vibspd=data>>4;
949 			dovibrato(this, c);
950 			break;
951 		case cmdGVolume:
952 			if (data<=128)
953 				this->gvol=data;
954 			putque(this, queGVol, -1, this->gvol);
955 			break;
956 		case cmdGVolSlide:
957 			if (data)
958 				c->gvolslide=data;
959 			this->gvolslide=data;
960 			this->gvol=range128(this->gvol+rowslide(c->gvolslide));
961 			putque(this, queGVol, -1, this->gvol);
962 			break;
963 		case cmdPanning:
964 			c->srnd=0;
965 			c->fpan=c->cpan=c->pan=(data+1)>>2;
966 			break;
967 		case cmdPanbrello:
968 			if (data&0xF)
969 				c->panbrdep=data&0xF;
970 			if (data>>4)
971 				c->panbrspd=data>>4;
972 			c->fx=ifxPanBrello;
973 			dopanbrello(this, c);
974 			break;
975 		case cmdMIDI:
976 			if (this->midicmds)
977 			{
978 				if (data&0x80)
979 					parsemidicmd(c, this->midicmds[data-103], 0);
980 				else
981 					parsemidicmd(c, this->midicmds[c->sfznum+9], data);
982 			}
983 			break;
984 		/* DEPRECATED - Zxx IS MIDI MACRO TRIGGER
985 		case cmdSync:
986 			putque(this, queSync, c->newchan.lch, data);
987 		*/
988 	}
989 }
990 
991 static void dovibrato(struct itplayer *this, struct it_logchan *c)
992 {
993 	int x;
994 	switch (c->vibtype)
995 	{
996 		case 0: x=sintab[4*(c->vibpos&63)]>>1; break;
997 		case 1: x=32-(c->vibpos&63); break;
998 		case 2: x=32-(c->vibpos&32); break;
999 		default: /* remove a warning */
1000 		case 3: x=(random(this)&63)-32;
1001 	}
1002 	if (this->curtick || !this->oldfx)
1003 	{
1004 		c->fpitch-=(c->vibdep*x)>>3;
1005 		c->vibpos-=c->vibspd;
1006 	}
1007 }
1008 
1009 static void dotremolo(struct itplayer *this, struct it_logchan *c)
1010 {
1011 	int x;
1012 	switch (c->tremtype)
1013 	{
1014 		case 0: x=sintab[4*(c->trempos&63)]>>1; break;
1015 		case 1: x=32-(c->trempos&63); break;
1016 		case 2: x=32-(c->trempos&32); break;
1017 		default: /* remove a warning */
1018 		case 3: x=(random(this)&63)-32;
1019 	}
1020 	c->fvol=range64(c->fvol+((c->tremdep*x)>>4));
1021 	c->trempos+=c->tremspd;
1022 }
1023 
1024 static void dopanbrello(struct itplayer *this, struct it_logchan *c)
1025 {
1026 	int x;
1027 
1028 	if (c->panbrtype==3)
1029 	{
1030 		if (c->panbrpos>=c->panbrspd)
1031 		{
1032 			c->panbrpos=0;
1033 			c->panbrrnd=random(this);
1034 		}
1035 		c->fpan=range64(c->fpan+((c->panbrdep*((c->panbrrnd&255)-128))>>6));
1036 	} else {
1037 		switch (c->panbrtype)
1038 		{
1039 			case 0: x=sintab[c->panbrpos&255]*2; break;
1040 			case 1: x=128-(c->panbrpos&255); break;
1041 			default: /* remove a warning */
1042 			case 2: x=128-2*(c->panbrpos&128); break;
1043 		}
1044 		c->fpan=range64(c->fpan+((c->panbrdep*x)>>6));
1045 	}
1046 	c->panbrpos+=c->panbrspd;
1047 }
1048 
1049 static void doportanote(struct itplayer *this, struct it_logchan *c, int v) /* if v, then do vporta, else eporta */
1050 {
1051 
1052 	if (!c->dpitch)
1053 		return;
1054 
1055 	if (c->pitch<c->dpitch)
1056 	{
1057 		if (v)
1058 			c->pitch+=(this->geffect?c->vportanote:c->vporta)*16;
1059 		else
1060 			c->pitch+=(this->geffect?c->eportanote:c->eporta)*16;
1061 
1062 		if (c->pitch>c->dpitch)
1063 			c->pitch=c->dpitch;
1064 	} else {
1065 		if (v)
1066 			c->pitch-=(this->geffect?c->vportanote:c->vporta)*16;
1067 		else
1068 			c->pitch-=(this->geffect?c->eportanote:c->eporta)*16;
1069 		if (c->pitch<c->dpitch)
1070 			c->pitch=c->dpitch;
1071 	}
1072 	c->fpitch=c->pitch;
1073 	if (c->pitch==c->dpitch)
1074 		c->dpitch=0;
1075 }
1076 
1077 static void dodelay(struct itplayer *this, struct it_logchan *c)
1078 {
1079 	if (this->curtick==c->specialdata)
1080 	{
1081 		if (c->delayed[0]||c->delayed[1])
1082 			playnote(this, c, c->delayed);
1083 		if (c->delayed[2])
1084 			playvcmd(this, c, c->delayed[2]);
1085 	} else if (((this->curtick+1)==(this->speed+this->patdelaytick))&&(!this->patdelayrow))
1086 	{
1087 /* Impulse Tracker has a bug where a too long delay affects the lastinstrument, even if no note were played.
1088  *
1089  * http://eval.sovietrussia.org/wiki/Player_abuse_tests#Out-of-range_note_delays
1090  */
1091 		if (c->delayed[1])
1092 			c->lastins=c->delayed[1];
1093 	}
1094 
1095 }
1096 
1097 static int rangepitch(struct itplayer *this, int p)
1098 {
1099 	return (p<this->pitchhigh)?this->pitchhigh:(p>this->pitchlow)?this->pitchlow:p;
1100 }
1101 
1102 static const uint16_t arpnotetab[] =
1103 {
1104 	32768, 30929, 29193, 27554,
1105 	26008, 24548, 23170, 21870,
1106 	20643, 19484, 18390, 17358,
1107 	16384, 15464, 14596, 13777
1108 };
1109 
1110 static void processfx(struct itplayer *this, struct it_logchan *c)
1111 {
1112 	switch (c->command)
1113 	{
1114 		case cmdSpeed:
1115 			break;
1116 		case cmdJump:
1117 			break;
1118 		case cmdBreak:
1119 			break;
1120 		case cmdVolSlide:
1121 			c->vol=range64(c->vol+tickslide(c->volslide));
1122 			break;
1123 		case cmdPortaD:
1124 			if (c->eporta>=0xE0)
1125 				break;
1126 			c->fpitch=c->pitch=rangepitch(this, c->pitch+c->eporta*16);
1127 			break;
1128 		case cmdPortaU:
1129 			if (c->eporta>=0xE0)
1130 				break;
1131 			c->fpitch=c->pitch=rangepitch(this, c->pitch-c->eporta*16);
1132 			if ((c->pitch==this->pitchhigh)&&c->pch)
1133 				c->pch->notecut=1;
1134 			break;
1135 		case cmdPortaNote:
1136 			doportanote(this, c, 0);
1137 			break;
1138 		case cmdVibrato:
1139 			dovibrato(this, c);
1140 			break;
1141 		case cmdTremor:
1142 			dotremor(c);
1143 			break;
1144 		case cmdArpeggio:
1145 			{
1146 				int arpnote;
1147 				switch (this->curtick%3)
1148 				{
1149 					default: /* remove a warning */
1150 					case 0:
1151 						arpnote=0;
1152 						break;
1153 					case 1:
1154 						arpnote=c->arpeggio1;
1155 						break;
1156 					case 2:
1157 						arpnote=c->arpeggio2;
1158 						break;
1159 				}
1160 				if (this->linear)
1161 					c->fpitch=c->fpitch-(arpnote<<8);
1162 				else
1163 					c->fpitch=(c->fpitch*arpnotetab[arpnote])>>15;
1164 				break;
1165 			}
1166 		case cmdPortaVol:
1167 			doportanote(this, c, 0);
1168 			c->fvol=c->vol=range64(c->vol+tickslide(c->volslide));
1169 			break;
1170 		case cmdVibVol:
1171 			dovibrato(this, c);
1172 			c->fvol=c->vol=range64(c->vol+tickslide(c->volslide));
1173 			break;
1174 		case cmdChanVol:
1175 			break;
1176 		case cmdChanVolSlide:
1177 			c->cvol=range64(c->cvol+tickslide(c->cvolslide));
1178 			break;
1179 		case cmdOffset:
1180 			break;
1181 		case cmdPanSlide:
1182 			c->fpan=c->cpan=c->pan=range64(c->pan-tickslide(c->panslide));
1183 			break;
1184 		case cmdRetrigger:
1185 			doretrigger(c);
1186 			break;
1187 		case cmdTremolo:
1188 			dotremolo(this, c);
1189 			break;
1190 		case cmdSpecial:
1191 			switch (c->specialcmd)
1192 			{
1193 				case cmdSVibType:
1194 					break;
1195 				case cmdSTremType:
1196 					break;
1197 				case cmdSPanbrType:
1198 					break;
1199 				case cmdSPatDelayTick:
1200 					break;
1201 				case cmdSInstFX:
1202 					break;
1203 				case cmdSPanning:
1204 					break;
1205 				case cmdSSurround:
1206 					break;
1207 				case cmdSOffsetHigh:
1208 					break;
1209 				case cmdSPatLoop:
1210 					break;
1211 				case cmdSNoteCut:
1212 					if ((this->curtick>=c->specialdata)&&c->pch&&(!this->patdelayrow))
1213 						c->pch->notecut=1;
1214 					break;
1215 				case cmdSNoteDelay:
1216 					dodelay(this, c);
1217 					break;
1218 				case cmdSPatDelayRow:
1219 					break;
1220 			}
1221 			break;
1222 		case cmdTempo:
1223 			if (c->tempo<0x20)
1224 			{
1225 				this->tempo+=(c->tempo<0x10)?-c->tempo:(c->tempo&0xF);
1226 				this->tempo=(this->tempo<0x20)?0x20:(this->tempo>0xFF)?0xFF:this->tempo;
1227 				putque(this, queTempo, -1, this->tempo);
1228 			}
1229 			break;
1230 		case cmdFineVib:
1231 			dovibrato(this, c);
1232 			break;
1233 		case cmdGVolume:
1234 			break;
1235 		case cmdGVolSlide:
1236 			this->gvol=range128(this->gvol+tickslide(c->gvolslide));
1237 			putque(this, queGVol, -1, this->gvol);
1238 			break;
1239 		case cmdPanning:
1240 			break;
1241 		case cmdPanbrello:
1242 			dopanbrello(this, c);
1243 			break;
1244 	}
1245 
1246 
1247 	if ((c->vcmd>=cmdVVolSlD)&&(c->vcmd<(cmdVVolSlD+10)))
1248 		c->fvol=c->vol=range64(c->vol-c->vvolslide);
1249 	else if ((c->vcmd>=cmdVVolSlU)&&(c->vcmd<(cmdVVolSlU+10)))
1250 		c->fvol=c->vol=range64(c->vol+c->vvolslide);
1251 	else if ((c->vcmd>=cmdVVibrato)&&(c->vcmd<(cmdVVibrato+10)))
1252 		dovibrato(this, c);
1253 	else if ((c->vcmd>=cmdVPortaNote)&&(c->vcmd<(cmdVPortaNote+10)))
1254 		doportanote(this, c, 1);
1255 	else if ((c->vcmd>=cmdVPortaU)&&(c->vcmd<(cmdVPortaU+10)))
1256 	{
1257 		c->fpitch=c->pitch=rangepitch(this, c->pitch-c->vporta*16);
1258 		if ((c->pitch==this->pitchhigh)&&c->pch)
1259 			c->pch->notecut=1;
1260 	} else if ((c->vcmd>=cmdVPortaD)&&(c->vcmd<(cmdVPortaD+10)))
1261 		c->fpitch=c->pitch=rangepitch(this, c->pitch+c->vporta*16);
1262 }
1263 
1264 static void inittickchan(struct it_physchan *p)
1265 {
1266 	p->fvol=p->vol;
1267 	p->fpan=p->pan;
1268 	p->fpitch=p->pitch;
1269 }
1270 
1271 static void inittick(struct it_logchan *c)
1272 {
1273 	c->fvol=c->vol;
1274 	c->fpan=c->pan;
1275 	c->fpitch=c->pitch;
1276 }
1277 
1278 static void initrow(struct it_logchan *c)
1279 {
1280 	c->command=0;
1281 	c->vcmd=0;
1282 }
1283 
1284 static void updatechan(struct it_logchan *c)
1285 {
1286 	struct it_physchan *p;
1287 	if (!c->pch)
1288 		return;
1289 	p=c->pch;
1290 	p->vol=(c->vol*c->cvol)>>4;
1291 	p->fvol=(c->fvol*c->cvol)>>4;
1292 	p->pan=c->pan*4-128;
1293 	p->fpan=c->fpan*4-128;
1294 	p->cutoff=c->cutoff;
1295 	p->fcutoff=c->fcutoff;
1296 	p->reso=c->reso;
1297 	p->pitch=-c->pitch;
1298 	p->fpitch=-c->fpitch;
1299 	p->srnd=c->srnd;
1300 }
1301 
1302 static int processenvelope(const struct it_envelope *env, int *pos, int noteoff, int env_type_active)
1303 {
1304 	int i, x;
1305 
1306 	for (i=0; i<env->len; i++)
1307 		if ((*pos)<env->x[i+1])
1308 			break;
1309 
1310 	if (env->x[i]==env->x[i+1] || (*pos)==env->x[i])
1311 		x=256*env->y[i];
1312 	else {
1313 		float s=(float)((*pos)-env->x[i])/(float)(env->x[i+1]-env->x[i]);
1314 		x=256.0*((1-s)*env->y[i]+s*env->y[i+1]);
1315 	}
1316 
1317 	if (env_type_active)
1318 		(*pos)++;
1319 
1320 	if (!noteoff&&(env->type&env_type_slooped))
1321 	{
1322 		if ((*pos)==(env->x[env->sloope]+1))
1323 			(*pos)=env->x[env->sloops];
1324 	} else if (env->type&env_type_looped)
1325 	{
1326 		if ((*pos)==(env->x[env->loope]+1))
1327 			(*pos)=env->x[env->loops];
1328 	}
1329 	if ((*pos)>env->x[env->len])
1330 		(*pos)=env->x[env->len];
1331 
1332 	return x;
1333 }
1334 
1335 static void processchan(struct itplayer *this, struct it_physchan *p)
1336 {
1337 	int x;
1338 
1339 	if (p->volenvpos||p->volenv)
1340 		p->fvol=(processenvelope(&p->inst->envs[0], &p->volenvpos, p->noteoff, p->volenv)*p->fvol)>>14;
1341 
1342 	if (p->volenv)
1343 	{
1344 		const struct it_envelope *env=&p->inst->envs[0];
1345 		if (p->noteoff&&(p->inst->envs[0].type&env_type_looped))
1346 			p->notefade=1;
1347 		if ((p->volenvpos==env->x[env->len])&&!(p->inst->envs[0].type&env_type_looped)&&(!(p->inst->envs[0].type&env_type_slooped)||p->noteoff))
1348 		{
1349 			if (!env->y[env->len])
1350 				p->notecut=1;
1351 			else
1352 				p->notefade=1;
1353 		}
1354 	} else
1355 		if (p->noteoff)
1356 			p->notefade=1;
1357 
1358 	p->fvol=(p->fvol*p->fadeval)>>10;
1359 	p->fadeval-=p->notefade?(p->fadeval>p->fadespd)?p->fadespd:p->fadeval:0;
1360 	if (!p->fadeval)
1361 		p->notecut=1;
1362 
1363 	p->fvol=(this->gvol*p->fvol)>>7;
1364 	p->fvol=(p->smp->gvl*p->fvol)>>6;
1365 	p->fvol=(p->inst->gbv*p->fvol)>>7;
1366 
1367 
1368 	if (p->panenvpos||p->panenv)
1369 		p->fpan+=processenvelope(&p->inst->envs[1], &p->panenvpos, p->noteoff, p->panenv)>>6;
1370 
1371 	if (p->srnd)
1372 		p->fpan=0;
1373 
1374 	p->fpan=(this->chsep*p->fpan)>>7;
1375 
1376 
1377 	if (p->pitchenvpos||p->pitchenv)
1378 	{
1379 		if (this->linear)
1380 			p->fpitch+=processenvelope(&p->inst->envs[2], &p->pitchenvpos, p->noteoff, p->pitchenv)>>1;
1381 		else {
1382 			int e=processenvelope(&p->inst->envs[2], &p->pitchenvpos, p->noteoff, p->pitchenv);
1383 			int e2;
1384 			int shl=0;
1385 			int shr=0;
1386 			int fac;
1387 			while (e>6144)
1388 			{
1389 				e-=6144;
1390 				shl++;
1391 			}
1392 			while (e<0)
1393 			{
1394 				e+=6144;
1395 				shr++;
1396 			}
1397 			e2=0x200-(e&0x1ff);
1398 			e>>=9;
1399 			fac=(e2*arpnotetab[12-e]+(512-e2)*arpnotetab[11-e])>>9;
1400 			fac>>=shr;
1401 			fac<<=shl;
1402 			p->fpitch=imuldiv(p->fpitch,16384,fac);
1403 		}
1404 	}
1405 
1406 	switch (p->smp->vit)
1407 	{
1408 		case 0: x=sintab[p->avibpos&255]*2; break;
1409 		case 1: x=128-(p->avibpos&255); break;
1410 		case 2: x=128-(p->avibpos&128); break;
1411 		default: /* remove a warning */
1412 		case 3: x=(random(this)&255)-128;
1413 	}
1414 	p->fpitch+=(x*p->avibdep)>>14;
1415 	p->avibpos+=p->smp->vis;
1416 	p->avibdep+=p->smp->vir;
1417 	if (p->avibdep>(p->smp->vid*256))
1418 		p->avibdep=p->smp->vid*256;
1419 
1420 	if (p->filterenvpos||p->filterenv)
1421 	{
1422 		p->fcutoff=p->cutoff&0x7f;
1423 		p->fcutoff*=processenvelope(&p->inst->envs[2], &p->filterenvpos, p->noteoff, p->filterenv)+8192;
1424 		p->fcutoff>>=14;
1425 		p->fcutoff|=0x80;
1426 	}
1427 
1428 }
1429 
1430 static void putchandata(struct itplayer *this, struct it_physchan *p)
1431 {
1432 	if (p->newsamp!=-1)
1433 	{
1434 		mcpSet(p->no, mcpCReset, 0);
1435 		mcpSet(p->no, mcpCInstrument, p->newsamp);
1436 		p->newsamp=-1;
1437 	}
1438 	if (p->newpos!=-1)
1439 	{
1440 		mcpSet(p->no, mcpCPosition, p->newpos);
1441 		mcpSet(p->no, mcpCLoop, 1);
1442 		mcpSet(p->no, mcpCDirect, 0);
1443 		mcpSet(p->no, mcpCStatus, 1);
1444 		p->newpos=-1;
1445 		p->dead=0;
1446 	}
1447 	if (p->noteoff&&!p->looptype)
1448 	{
1449 		mcpSet(p->no, mcpCLoop, 2);
1450 		p->looptype=1;
1451 	}
1452 	if (this->linear)
1453 		mcpSet(p->no, mcpCPitch, p->fpitch);
1454 	else
1455 		mcpSet(p->no, mcpCPitch6848, -p->fpitch);
1456 
1457 	mcpSet(p->no, mcpCVolume, p->fvol);
1458 	mcpSet(p->no, mcpCPanning, p->fpan);
1459 	mcpSet(p->no, mcpCSurround, p->srnd);
1460 	mcpSet(p->no, mcpCMute, this->channels[p->lch].mute);
1461 	mcpSet(p->no, mcpCFilterFreq, p->fcutoff);
1462 	mcpSet(p->no, mcpCFilterRez, p->reso);
1463 }
1464 
1465 void __attribute__ ((visibility ("internal"))) mutechan(struct itplayer *this, int c, int m)
1466 {
1467 	if ((c>=0)||(c<this->nchan))
1468 		this->channels[c].mute=m;
1469 }
1470 
1471 static void allocatechan(struct itplayer *this, struct it_logchan *c)
1472 {
1473 	int i;
1474 
1475 	if (c->disabled)
1476 	{
1477 		c->pch=0;
1478 		return;
1479 	}
1480 	for (i=0; i<this->npchan; i++)
1481 		if (this->pchannels[i].lch==-1)
1482 			break;
1483 
1484 	if (i==this->npchan)
1485 		for (i=0; i<this->npchan; i++)
1486 			if (this->pchannels[i].dead)
1487 				break;
1488 
1489 	/* search for most silent NNAed channel */
1490 	if (i==this->npchan)
1491 	{
1492 		int bestpch=this->npchan;
1493 		int bestvol=0xffffff;
1494 		for (i=0; i<this->npchan; i++)
1495 			if ((this->pchannels[i].notecut || this->pchannels[i].noteoff || this->pchannels[i].notefade) && this->pchannels[i].fvol<=bestvol)
1496 			{
1497 				bestpch=i;
1498 				bestvol=this->pchannels[i].fvol;
1499 			}
1500 		i=bestpch;
1501 	}
1502 
1503 	/* when everything fails, search for channel with lowest vol */
1504 	if (i==this->npchan)
1505 	{
1506 		int bestpch=this->npchan;
1507 		int bestvol=c->newchan.fvol;
1508 		for (i=0; i<this->npchan; i++)
1509 			if (this->pchannels[i].fvol<bestvol )
1510 			{
1511 				bestpch=i;
1512 				bestvol=this->pchannels[i].fvol;
1513 			}
1514 		i=bestpch;
1515 	}
1516 
1517 	if (i<this->npchan)
1518 	{
1519 		if (this->pchannels[i].lch!=-1)
1520 		{
1521 			if (this->channels[this->pchannels[i].lch].pch==&this->pchannels[i])
1522 				this->channels[this->pchannels[i].lch].pch=0;
1523 		}
1524 		this->pchannels[i]=c->newchan;
1525 		this->pchannels[i].lchp=c;
1526 		this->pchannels[i].no=i;
1527 		c->pch=&this->pchannels[i];
1528 	} else
1529 		c->pch=0;
1530 
1531 }
1532 
1533 static void getproctime(struct itplayer *this)
1534 {
1535 	this->proctime=mcpGet(-1, mcpGCmdTimer);
1536 }
1537 
1538 static void putglobdata(struct itplayer *this)
1539 {
1540 	mcpSet(-1, mcpGSpeed, 256*2*this->tempo/5);
1541 }
1542 
1543 static void putque(struct itplayer *this, int type, int val1, int val2)
1544 {
1545 	if (((this->quewpos+1)%this->quelen)==this->querpos)
1546 		return;
1547 	this->que[this->quewpos][0]=this->proctime;
1548 	this->que[this->quewpos][1]=type;
1549 	this->que[this->quewpos][2]=val1;
1550 	this->que[this->quewpos][3]=val2;
1551 	this->quewpos=(this->quewpos+1)%this->quelen;
1552 }
1553 
1554 static int gettime(void)
1555 {
1556 	return mcpGet(-1, mcpGTimer);
1557 }
1558 
1559 static void readque(struct itplayer *this)
1560 {
1561 	int i;
1562 	int time=gettime();
1563 	while (1)
1564 	{
1565 		int t, val1, val2;
1566 		if (this->querpos==this->quewpos)
1567 			break;
1568 		t=this->que[this->querpos][0];
1569 		if (time<t)
1570 			break;
1571 		val1=this->que[this->querpos][2];
1572 		val2=this->que[this->querpos][3];
1573 		switch (this->que[this->querpos][1])
1574 		{
1575 			case queSync:
1576 				this->realsync=val2;
1577 				this->realsynctime=t;
1578 				this->channels[val1].realsync=val2;
1579 				this->channels[val1].realsynctime=t;
1580 				break;
1581 			case quePos:
1582 				this->realpos=val2;
1583 				for (i=0; i<this->nchan; i++)
1584 				{
1585 					struct it_logchan *c=&this->channels[i];
1586 					if (c->evpos==-1)
1587 					{
1588 						if (c->evpos0==this->realpos)
1589 						{
1590 							c->evpos=this->realpos;
1591 							c->evtime=t;
1592 						}
1593 					} else {
1594 						switch (c->evmodtype)
1595 						{
1596 							case 1:
1597 								c->evmodpos++;
1598 								break;
1599 							case 2:
1600 								if (!(this->realpos&0xFF))
1601 									c->evmodpos++;
1602 								break;
1603 							case 3:
1604 								if (!(this->realpos&0xFFFF))
1605 									c->evmodpos++;
1606 								break;
1607 						}
1608 						if ((c->evmodpos==c->evmod)&&c->evmod)
1609 						{
1610 							c->evmodpos=0;
1611 							c->evpos=this->realpos;
1612 							c->evtime=t;
1613 						}
1614 					}
1615 				}
1616 				break;
1617 			case queGVol: this->realgvol=val2; break;
1618 			case queTempo: this->realtempo=val2; break;
1619 			case queSpeed: this->realspeed=val2; break;
1620 		};
1621 		this->querpos=(this->querpos+1)%this->quelen;
1622 	}
1623 }
1624 
1625 static void checkchan(struct itplayer *this, struct it_physchan *p)
1626 {
1627 	if (!mcpGet(p->no, mcpCStatus))
1628 		p->dead=1;
1629 	if (p->dead&&(this->channels[p->lch].pch!=p))
1630 		p->notecut=1;
1631 	if (p->notecut)
1632 	{
1633 		if (this->channels[p->lch].pch==p)
1634 			this->channels[p->lch].pch=0;
1635 		p->lch=-1;
1636 		mcpSet(p->no, mcpCReset, 0);
1637 		return;
1638 	}
1639 }
1640 
1641 static void playtick(struct itplayer *this)
1642 {
1643 	int i;
1644 
1645 	if (!this->npchan)
1646 		return;
1647 
1648 	getproctime(this);
1649 	readque(this);
1650 
1651 	for (i=0; i<this->nchan; i++)
1652 		inittick(&this->channels[i]);
1653 
1654 	if (this->looped&&this->noloop)
1655 		return;
1656 
1657 	this->curtick++;
1658 	if ((this->curtick==(this->speed+this->patdelaytick))&&this->patdelayrow)
1659 	{
1660 		this->curtick=0;
1661 		this->patdelayrow--;
1662 	}
1663 
1664 	if (this->curtick==(this->speed+this->patdelaytick))
1665 	{
1666 		this->patdelaytick=0;
1667 		this->curtick=0;
1668 		for (i=0; i<this->nchan; i++)
1669 		{
1670 			struct it_logchan *ch=&this->channels[i];
1671 			ch->fnotehit=0;
1672 			ch->fvolslide=0;
1673 			ch->fpitchslide=0;
1674 			ch->fpanslide=0;
1675 			ch->fpitchfx=0;
1676 			ch->fvolfx=0;
1677 			ch->fnotefx=0;
1678 			ch->fx=0;
1679 		}
1680 		this->currow++;
1681 		if ((this->gotoord==-1)&&(this->currow==this->patlens[this->orders[this->curord]]))
1682 		{
1683 			this->gotoord=this->curord+1;
1684 			this->gotorow=0;
1685 		}
1686 		if (this->gotoord!=-1)
1687 		{
1688 			if (this->gotoord!=this->curord)
1689 				for (i=0; i<this->nchan; i++)
1690 				{
1691 					struct it_logchan *c=&this->channels[i];
1692 					c->patloopcount=0;
1693 					c->patloopstart=0;
1694 				}
1695 			if (this->gotoord>=this->endord)
1696 			{
1697 				this->gotoord=0;
1698 				if (!this->manualgoto && this->noloop)
1699 					this->looped=1;
1700 				for (i=0; i<this->nchan; i++)
1701 				{
1702 					struct it_logchan *c=&this->channels[i];
1703 					c->retrigspd=1;
1704 					c->tremoron=1;
1705 					c->tremoroff=1;
1706 					c->tremoroncounter=0;
1707 					c->tremoroffcounter=0;
1708 				}
1709 			}
1710 			while (this->orders[this->gotoord]==0xFFFF)
1711 				this->gotoord++;
1712 			if (this->gotoord==this->endord)
1713 				this->gotoord=0;
1714 			if (this->gotorow>=this->patlens[this->orders[this->gotoord]])
1715 			{
1716 				this->gotoord++;
1717 				this->gotorow=0;
1718 				while (this->orders[this->gotoord]==0xFFFF)
1719 					this->gotoord++;
1720 				if (this->gotoord==this->endord)
1721 					this->gotoord=0;
1722 			}
1723 			this->curord=this->gotoord;
1724 			this->patptr=this->patterns[this->orders[this->curord]];
1725 			for (this->currow=0; this->currow<this->gotorow; this->currow++)
1726 			{
1727 				while (*this->patptr)
1728 					this->patptr+=6;
1729 				this->patptr++;
1730 			}
1731 			this->gotoord=-1;
1732 		}
1733 
1734 		if (this->looped&&this->noloop)
1735 		{
1736 			for (i=0; i<this->nchan; i++)
1737 			{
1738 				mutechan(this, i, 1);
1739 				updatechan(&this->channels[i]);
1740 			}
1741 			return;
1742 		}
1743 
1744 		for (i=0; i<this->nchan; i++)
1745 			initrow(&this->channels[i]);
1746 		while (*this->patptr)
1747 		{
1748 			struct it_logchan *c=&this->channels[*this->patptr++-1];
1749 			int delay;
1750 			if ((this->patptr[3]==cmdSpecial)&&this->patptr[4])
1751 			{
1752 				c->specialcmd=this->patptr[4]>>4;
1753 				c->specialdata=this->patptr[4]&0xF;
1754 			}
1755 			if ((this->patptr[3]==cmdSpecial)&&(c->specialcmd==cmdSNoteDelay))
1756 			{
1757 				memcpy(c->delayed, this->patptr, /*sizeof(c->delayed)*/5); /* else we might read unknown unmapped memory */
1758 				delay=1;
1759 			} else {
1760 				if (this->patptr[0]||this->patptr[1])
1761 					playnote(this, c, this->patptr);
1762 				delay=0;
1763 			}
1764 			if (this->patptr[3])
1765 				playcmd(this, c, this->patptr[3], this->patptr[4]); /* we need notedata to know if Portamento should do anything */
1766 			if (!delay)
1767 				if (this->patptr[2])
1768 					playvcmd(this, c, this->patptr[2]);
1769 			this->patptr+=5;
1770 		}
1771 		this->patptr++;
1772 		if (this->patdelayrow) /* in case, the first SEx command was SE0, we fetch this by storing SEx+1 to this->patdelayrow */
1773 			this->patdelayrow--;
1774 	} else
1775 		for (i=0; i<this->nchan; i++)
1776 			processfx(this, &this->channels[i]);
1777 
1778 	this->manualgoto=0;
1779 	this->gvolslide=0;
1780 
1781 	for (i=0; i<this->npchan; i++)
1782 		inittickchan(&this->pchannels[i]);
1783 	for (i=0; i<this->nchan; i++)
1784 		updatechan(&this->channels[i]);
1785 	for (i=0; i<this->npchan; i++)
1786 		if (this->pchannels[i].lch!=-1)
1787 			checkchan(this, &this->pchannels[i]);
1788 	for (i=0; i<this->npchan; i++)
1789 		if (this->pchannels[i].lch!=-1)
1790 			processchan(this, &this->pchannels[i]);
1791 	for (i=0; i<this->nchan; i++)
1792 		if (this->channels[i].pch==&this->channels[i].newchan)
1793 		{
1794 			processchan(this, this->channels[i].pch);
1795 			allocatechan(this, &this->channels[i]);
1796 		}
1797 	for (i=0; i<this->npchan; i++)
1798 		if (this->pchannels[i].lch!=-1)
1799 			putchandata(this, &this->pchannels[i]);
1800 
1801 	putglobdata(this);
1802 	putque(this, quePos, -1, (this->curtick&0xFF)|(this->currow<<8)|(this->curord<<16));
1803 }
1804 
1805 int __attribute__ ((visibility ("internal"))) loadsamples(struct it_module *m)
1806 {
1807 	return mcpLoadSamples(m->sampleinfos, m->nsampi);
1808 }
1809 
1810 int __attribute__ ((visibility ("internal"))) play(struct itplayer *this, const struct it_module *m, int ch, struct ocpfilehandle_t *file)
1811 {
1812 	int i;
1813 	staticthis=this;
1814 
1815 	this->randseed=1;
1816 	this->patdelayrow=0;
1817 	this->patdelaytick=0;
1818 	this->gotoord=0;
1819 	this->gotorow=0;
1820 	this->endord=m->endord;
1821 	this->nord=m->nord;
1822 	this->nchan=m->nchan;
1823 	this->orders=m->orders;
1824 	this->patlens=m->patlens;
1825 	this->patterns=m->patterns;
1826 	this->ninst=m->ninst;
1827 	this->instruments=m->instruments;
1828 	this->nsamp=m->nsamp;
1829 	this->samples=m->samples;
1830 	this->sampleinfos=m->sampleinfos;
1831 	this->nsampi=m->nsampi;
1832 	this->midicmds=m->midicmds;
1833 	this->speed=m->inispeed;
1834 	this->tempo=m->initempo;
1835 	this->gvol=m->inigvol;
1836 	this->chsep=m->chsep;
1837 	this->linear=m->linear;
1838 	this->oldfx=!!m->oldfx;
1839 	this->instmode=m->instmode;
1840 	this->geffect=m->geffect;
1841 	this->curtick=this->speed-1;
1842 	this->currow=0;
1843 	this->realpos=0;
1844 	this->pitchhigh=-0x6000;
1845 	this->pitchlow=0x6000;
1846 	this->realsynctime=0;
1847 	this->realsync=0;
1848 	this->realtempo=this->tempo;
1849 	this->realspeed=this->speed;
1850 	this->realgvol=this->gvol;
1851 
1852 	this->curord=0;
1853 	while (this->orders[this->curord]==0xFFFF && this->curord<this->nord)
1854 		this->curord++;
1855 
1856 	if (this->curord==this->nord)
1857 		return 0;
1858 
1859 	this->channels=malloc(sizeof(struct it_logchan)*this->nchan);
1860 	this->pchannels=malloc(sizeof(struct it_physchan)*ch);
1861 	this->quelen=500;
1862 	this->que=malloc(sizeof(int)*this->quelen*4);
1863 	if (!this->channels||!this->pchannels||!this->que)
1864 	{
1865 		if (this->channels)
1866 		{
1867 			free(this->channels);
1868 			this->channels=NULL;
1869 		};
1870 		if (this->pchannels)
1871 		{
1872 			free(this->pchannels);
1873 			this->pchannels=NULL;
1874 		}
1875 		if (this->que)
1876 		{
1877 			free(this->que);
1878 			this->que=NULL;
1879 		}
1880 		return 0;
1881 	}
1882 	this->querpos=this->quewpos=0;
1883 	memset(this->channels, 0, sizeof(*this->channels)*this->nchan);
1884 	memset(this->pchannels, 0, sizeof(*this->pchannels)*ch);
1885 	for (i=0; i<ch; i++)
1886 		this->pchannels[i].lch=-1;
1887 	for (i=0; i<this->nchan; i++)
1888 	{
1889 		struct it_logchan *c=&this->channels[i];
1890 		c->newchan.lch=i;
1891 		c->cvol=m->inivol[i];
1892 		c->cpan=m->inipan[i]&127;
1893 		c->srnd=c->cpan==100;
1894 		c->disabled=m->inipan[i]&128;
1895 		c->retrigspd=1;
1896 		c->tremoron=1;
1897 		c->tremoroff=1;
1898 		c->tremoroncounter=0;
1899 		c->tremoroffcounter=0;
1900 	}
1901 
1902 	if (!mcpOpenPlayer(ch, playtickstatic, file))
1903 		return 0;
1904 
1905 	this->npchan=mcpNChan;
1906 
1907 	return 1;
1908 }
1909 
1910 void __attribute__ ((visibility ("internal"))) stop(struct itplayer *this)
1911 {
1912 	mcpClosePlayer();
1913 	if (this->channels)
1914 	{
1915 		free(this->channels);
1916 		this->channels=NULL;
1917 	};
1918 	if (this->pchannels)
1919 	{
1920 		free(this->pchannels);
1921 		this->pchannels=NULL;
1922 	}
1923 	if (this->que)
1924 	{
1925 		free(this->que);
1926 		this->que=NULL;
1927 	}
1928 }
1929 
1930 int __attribute__ ((visibility ("internal"))) getpos(struct itplayer *this)
1931 {
1932 	if (this->manualgoto)
1933 		return (this->gotorow<<8)|(this->gotoord<<16);
1934 	return (this->curtick&0xFF)|(this->currow<<8)|(this->curord<<16);
1935 }
1936 
1937 int __attribute__ ((visibility ("internal"))) getrealpos(struct itplayer *this)
1938 {
1939 	readque(this);
1940 	return this->realpos;
1941 }
1942 
1943 int __attribute__ ((visibility ("internal"))) getchansample(struct itplayer *this, int ch, int16_t *buf, int len, uint32_t rate, int opt)
1944 {
1945 	int i,n;
1946 	unsigned int chn[64];
1947 	n=0;
1948 	for (i=0; i<this->npchan; i++)
1949 		if (this->pchannels[i].lch==ch)
1950 			chn[n++]=i;
1951 	mcpMixChanSamples(chn, n, buf, len, rate, opt);
1952 	return 1;
1953 }
1954 
1955 void __attribute__ ((visibility ("internal"))) itplayer_getrealvol(struct itplayer *this, int ch, int *l, int *r)
1956 {
1957 	int i, voll, volr;
1958 
1959 	*l = *r = 0;
1960 
1961 	for (i=0; i<this->npchan; i++)
1962 		if (this->pchannels[i].lch==ch)
1963 		{
1964 			mcpGetRealVolume(i, &voll, &volr);
1965 			(*l)+=voll;
1966 			(*r)+=volr;
1967 		}
1968 }
1969 
1970 void __attribute__ ((visibility ("internal"))) setpos(struct itplayer *this, int ord, int row)
1971 {
1972 	int i;
1973 	if (this->curord!=ord)
1974 		for (i=0; i<this->npchan; i++)
1975 			this->pchannels[i].notecut=1;
1976 	this->curtick=this->speed-1;
1977 	this->patdelaytick=0;
1978 	this->patdelayrow=0;
1979 	if ((ord==this->curord)&&(row>this->patlens[this->orders[this->curord]]))
1980 	{
1981 		row=0;
1982 		ord++;
1983 	}
1984 	this->gotorow=(row>0xFF)?0xFF:(row<0)?0:row;
1985 	this->gotoord=((ord>=this->nord)||(ord<0))?0:ord;
1986 	this->manualgoto=1;
1987 	this->querpos=this->quewpos=0;
1988 	this->realpos=(this->gotorow<<8)|(this->gotoord<<16);
1989 }
1990 
1991 int __attribute__ ((visibility ("internal"))) getdotsdata(struct itplayer *this, int ch, int pch, int *smp, int *note, int *voll, int *volr, int *sus)
1992 {
1993 	struct it_physchan *p;
1994 	for (; pch<this->npchan; pch++)
1995 		if ((this->pchannels[pch].lch==ch)&&!this->pchannels[pch].dead)
1996 			break;
1997 	if (pch>=this->npchan)
1998 		return -1;
1999 	p=&this->pchannels[pch];
2000 	*smp=p->smp->handle;
2001 
2002 	if (this->linear)
2003 		*note=p->noteoffset+p->fpitch;
2004 	else
2005 		if (p->noteoffset+p->fpitch)
2006 			*note=p->noteoffset+mcpGetNote8363(6848*8363/p->fpitch);
2007 		else
2008 			*note=0;
2009 
2010 	mcpGetRealVolume(p->no, voll, volr);
2011 	*sus=!(p->noteoff||p->notefade);
2012 	return pch+1;
2013 }
2014 
2015 void __attribute__ ((visibility ("internal"))) getglobinfo(struct itplayer *this, int *tmp, int *bp, int *gv, int *gs)
2016 {
2017 	readque(this);
2018 	*tmp=this->realspeed;
2019 	*bp=this->realtempo;
2020 	*gv=this->realgvol;
2021 	*gs=this->gvolslide?(this->gvolslide>0?ifxGVSUp:ifxGVSDown):0;
2022 }
2023 
2024 int __attribute__ ((visibility ("internal"))) getsync(struct itplayer *this, int ch, int *time)
2025 {
2026 	readque(this);
2027 	if ((ch<0)||(ch>=this->nchan))
2028 	{
2029 		*time=gettime()-this->realsynctime;
2030 		return this->realsync;
2031 	} else {
2032 		*time=gettime()-this->channels[ch].realsynctime;
2033 		return this->channels[ch].realsync;
2034 	}
2035 }
2036 /*
2037 int __attribute__ ((visibility ("internal"))) getticktime(struct itplayer *this)
2038 {
2039 	readque(this);
2040 	return 65536*5/(2*this->realtempo);
2041 }
2042 
2043 int __attribute__ ((visibility ("internal"))) getrowtime(struct itplayer *this)
2044 {
2045 	readque(this);
2046 	return 65536*5*this->realspeed/(2*this->realtempo);
2047 }*/
2048 /*
2049 void __attribute__ ((visibility ("internal"))) setevpos(struct itplayer *this, int ch, int pos, int modtype, int mod)
2050 {
2051 	struct it_logchan *c;
2052 	if ((ch<0)||(ch>=this->nchan))
2053 		return;
2054 	c=&this->channels[ch];
2055 	c->evpos0=pos;
2056 	c->evmodtype=modtype;
2057 	c->evmod=mod;
2058 	c->evmodpos=0;
2059 	c->evpos=-1;
2060 	c->evtime=-1;
2061 }
2062 */
2063 /*
2064 int __attribute__ ((visibility ("internal"))) getevpos(struct itplayer *this, int ch, int *time)
2065 {
2066 	readque(this);
2067 	if ((ch<0)||(ch>=this->nchan))
2068 	{
2069 		*time=-1;
2070 		return -1;
2071 	}
2072 	*time=gettime()-this->channels[ch].evtime;
2073 	return this->channels[ch].evpos;
2074 }
2075 */
2076 /*
2077 int __attribute__ ((visibility ("internal"))) findevpos(struct itplayer *this, int pos, int *time)
2078 {
2079 	int i;
2080 	readque(this);
2081 	for (i=0; i<this->nchan; i++)
2082 		if (this->channels[i].evpos==pos)
2083 			break;
2084 	*time=gettime()-this->channels[i].evtime;
2085 	return this->channels[i].evpos;
2086 }
2087 */
2088 
2089 void __attribute__ ((visibility ("internal"))) setloop(struct itplayer *this, int s)
2090 {
2091 	this->noloop=!s;
2092 }
2093 
2094 int __attribute__ ((visibility ("internal"))) getloop(struct itplayer *this)
2095 {
2096 	return this->looped;
2097 }
2098 
2099 int __attribute__ ((visibility ("internal"))) chanactive(struct itplayer *this, int ch, int *lc)
2100 {
2101 	struct it_physchan *p=&this->pchannels[ch];
2102 	*lc=p->lch;
2103 	if (!(*lc>-1)&&p->smp&&p->fvol)
2104 		return 0; /* force mcpGet to be checked last - stian */
2105 	return mcpGet(ch, mcpCStatus);
2106 }
2107 
2108 int __attribute__ ((visibility ("internal"))) lchanactive(struct itplayer *this, int lc)
2109 {
2110 	struct it_physchan *p=this->channels[lc].pch;
2111 	if (!p)
2112 		return 0; /* avoid strange crashes on some archs - stian */
2113 	if (!(p->smp&&p->fvol))
2114 		return 0; /* force mcpGet to be checked last - stian */
2115 	return mcpGet(p->no, mcpCStatus);
2116 }
2117 
2118 int __attribute__ ((visibility ("internal"))) getchanins(struct itplayer *this, int ch)
2119 {
2120 	struct it_physchan *p=&this->pchannels[ch];
2121 	return p->inst->handle+1;
2122 }
2123 
2124 int __attribute__ ((visibility ("internal"))) getchansamp(struct itplayer *this, int ch)
2125 {
2126 	struct it_physchan *p=&this->pchannels[ch];
2127 	if (!p->smp)
2128 		return 0xFFFF;
2129 	return p->smp->handle;
2130 }
2131 
2132 
2133 void __attribute__ ((visibility ("internal"))) getchaninfo(struct itplayer *this, uint8_t ch, struct it_chaninfo *ci)
2134 {
2135 	const struct it_logchan *t=&this->channels[ch];
2136 	if (t->pch)
2137 	{
2138 		ci->ins=getchanins(this, t->pch->no);
2139 		ci->smp=getchansamp(this, t->pch->no);
2140 		ci->note=t->curnote+11;
2141 		ci->vol=t->vol;
2142 		if (!t->pch->fadeval)
2143 			ci->vol=0;
2144 		ci->pan=t->srnd?16:t->pan>>2;
2145 		ci->notehit=t->fnotehit;
2146 		ci->volslide=t->fvolslide;
2147 		ci->pitchslide=t->fpitchslide;
2148 		ci->panslide=t->fpanslide;
2149 		ci->volfx=t->fvolfx;
2150 		ci->pitchfx=t->fpitchfx;
2151 		ci->notefx=t->fnotefx;
2152 		ci->fx=t->fx;
2153 	} else
2154 		memset(ci, 0, sizeof(*ci));
2155 }
2156 
2157 int __attribute__ ((visibility ("internal"))) getchanalloc(struct itplayer *this, uint8_t ch)
2158 {
2159 	int num=0;
2160 	int i;
2161 	for (i=0; i<this->npchan; i++)
2162 	{
2163 		struct it_physchan *p=&this->pchannels[i];
2164 		if (p->lch==ch && !p->dead)
2165 			num++;
2166 	}
2167 	return num;
2168 }
2169