static int process_effects()

in doom_py/src/vizdoom/dumb/src/it/itrender.c [2171:3162]


static int process_effects(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry, int ignore_cxx)
{
	DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
	IT_PLAYING *playing;
	int i;

	IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];

	if (entry->mask & IT_ENTRY_EFFECT) {
		switch (entry->effect) {
/*
Notes about effects (as compared to other module formats)

C               This is now in *HEX*. (Used to be in decimal in ST3)
E/F/G/H/U       You need to check whether the song uses Amiga/Linear slides.
H/U             Vibrato in Impulse Tracker is two times finer than in
                any other tracker and is updated EVERY tick.
                If "Old Effects" is *ON*, then the vibrato is played in the
                normal manner (every non-row tick and normal depth)
E/F/G           These commands ALL share the same memory.
Oxx             Offsets to samples are to the 'xx00th' SAMPLE. (ie. for
                16 bit samples, the offset is xx00h*2)
                Oxx past the sample end will be ignored, unless "Old Effects"
                is ON, in which case the Oxx will play from the end of the
                sample.
Yxy             This uses a table 4 times larger (hence 4 times slower) than
                vibrato or tremelo. If the waveform is set to random, then
                the 'speed' part of the command is interpreted as a delay.
*/
			case IT_SET_SPEED:
				if (entry->effectvalue)
				{
					/*if (entry->effectvalue == 255)
						if (sigrenderer->callbacks->xm_speed_zero && (*sigrenderer->callbacks->xm_speed_zero)(sigrenderer->callbacks->xm_speed_zero_data))
							return 1;*/
					if (sigdata->flags & IT_WAS_AN_STM) {
						int n = entry->effectvalue;
						if (n >= 32) {
							sigrenderer->tick = sigrenderer->speed = n;
						}
					} else {
						sigrenderer->tick = sigrenderer->speed = entry->effectvalue;
					}
				}
				else if ((sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD)) == IT_WAS_AN_XM) {
#ifdef BIT_ARRAY_BULLSHIT
					bit_array_set(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row);
#endif
					sigrenderer->speed = 0;
					if (sigrenderer->callbacks->xm_speed_zero && (*sigrenderer->callbacks->xm_speed_zero)(sigrenderer->callbacks->xm_speed_zero_data))
						return 1;
				}
				break;

			case IT_BREAK_TO_ROW:
				if (ignore_cxx) break;
				sigrenderer->breakrow = entry->effectvalue;
				/* XXX jump and break on the same row */
				if ( ( ( sigrenderer->processrow | 0xC00 ) == 0xFFFE ) &&
					! ( sigrenderer->processrow & 0x400 ) ) {
					sigrenderer->processrow = 0xFFFE & ~0xC00;
				} else {
					sigrenderer->processorder = sigrenderer->order;
					sigrenderer->processrow = 0xFFFE & ~0x800;
				}
				break;

			case IT_VOLSLIDE_VIBRATO:
				for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) {
					if (i < 0) playing = channel->playing;
					else {
						playing = sigrenderer->playing[i];
						if (!playing || playing->channel != channel) continue;
					}
					if (playing) {
						playing->vibrato_speed = channel->lastHspeed;
						playing->vibrato_depth = channel->lastHdepth;
						playing->vibrato_n++;
					}
				}
				/* Fall through and process volume slide. */
			case IT_VOLUME_SLIDE:
			case IT_VOLSLIDE_TONEPORTA:
				/* The tone portamento component is handled elsewhere. */
				{
					unsigned char v = entry->effectvalue;
					if (!(sigdata->flags & IT_WAS_A_MOD)) {
						if (v == 0)
							v = channel->lastDKL;
						channel->lastDKL = v;
					}
					if (!(sigdata->flags & IT_WAS_AN_XM)) {
						int clip = (sigdata->flags & IT_WAS_AN_S3M) ? 63 : 64;
						if ((v & 0x0F) == 0x0F) {
							if (!(v & 0xF0)) {
								channel->volslide = -15;
								channel->volume -= 15;
								if (channel->volume > clip) channel->volume = 0;
							} else {
								channel->volume += v >> 4;
								if (channel->volume > clip) channel->volume = clip;
							}
						} else if ((v & 0xF0) == 0xF0) {
							if (!(v & 0x0F)) {
								channel->volslide = 15;
								channel->volume += 15;
								if (channel->volume > clip) channel->volume = clip;
							} else {
								channel->volume -= v & 15;
								if (channel->volume > clip) channel->volume = 0;
							}
						} else if (!(v & 0x0F)) {
							channel->volslide = v >> 4;
						} else {
							channel->volslide = -(v & 15);
						}
					} else {
						if ((v & 0x0F) == 0) { /* Dx0 */
							channel->volslide = v >> 4;
						} else if ((v & 0xF0) == 0) { /* D0x */
							channel->volslide = -v;
						} else if ((v & 0x0F) == 0x0F) { /* DxF */
							channel->volume += v >> 4;
							if (channel->volume > 64) channel->volume = 64;
						} else if ((v & 0xF0) == 0xF0) { /* DFx */
							channel->volume -= v & 15;
							if (channel->volume > 64) channel->volume = 0;
						}
					}
				}
				break;
			case IT_XM_FINE_VOLSLIDE_DOWN:
				{
					unsigned char v = entry->effectvalue;
					if (v == 0)
						v = channel->xm_lastEB;
					channel->xm_lastEB = v;
					channel->volume -= v;
					if (channel->volume > 64) channel->volume = 0;
				}
				break;
			case IT_XM_FINE_VOLSLIDE_UP:
				{
					unsigned char v = entry->effectvalue;
					if (v == 0)
						v = channel->xm_lastEA;
					channel->xm_lastEA = v;
					channel->volume += v;
					if (channel->volume > 64) channel->volume = 64;
				}
				break;
			case IT_PORTAMENTO_DOWN:
				{
					unsigned char v = entry->effectvalue;
					if (sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_669)) {
						if (!(sigdata->flags & IT_WAS_A_MOD)) {
							if (v == 0xF0)
								v |= channel->xm_lastE2;
							else if (v >= 0xF0)
								channel->xm_lastE2 = v & 15;
							else if (v == 0xE0)
								v |= channel->xm_lastX2;
							else
								channel->xm_lastX2 = v & 15;
						}
					} else if (sigdata->flags & IT_WAS_AN_S3M) {
						if (v == 0)
							v = channel->lastDKL;
						channel->lastDKL = v;
					} else {
						if (v == 0)
							v = channel->lastEF;
						channel->lastEF = v;
					}
					for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) {
						if (i < 0) playing = channel->playing;
						else {
							playing = sigrenderer->playing[i];
							if (!playing || playing->channel != channel) continue;
						}
						if (playing) {
							if ((v & 0xF0) == 0xF0)
								playing->slide -= (v & 15) << 4;
							else if ((v & 0xF0) == 0xE0)
								playing->slide -= (v & 15) << 2;
							else if (i < 0 && sigdata->flags & IT_WAS_A_669)
								channel->portamento -= v << 3;
							else if (i < 0)
								channel->portamento -= v << 4;
						}
					}
				}
				break;
			case IT_PORTAMENTO_UP:
				{
					unsigned char v = entry->effectvalue;
					if (sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_669)) {
						if (!(sigdata->flags & IT_WAS_A_MOD)) {
							if (v == 0xF0)
								v |= channel->xm_lastE1;
							else if (v >= 0xF0)
								channel->xm_lastE1 = v & 15;
							else if (v == 0xE0)
								v |= channel->xm_lastX1;
							else
								channel->xm_lastX1 = v & 15;
						}
					} else if (sigdata->flags & IT_WAS_AN_S3M) {
						if (v == 0)
							v = channel->lastDKL;
						channel->lastDKL = v;
					} else {
						if (v == 0)
							v = channel->lastEF;
						channel->lastEF = v;
					}
					for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) {
						if (i < 0) playing = channel->playing;
						else {
							playing = sigrenderer->playing[i];
							if (!playing || playing->channel != channel) continue;
						}
						if (playing) {
							if ((v & 0xF0) == 0xF0)
								playing->slide += (v & 15) << 4;
							else if ((v & 0xF0) == 0xE0)
								playing->slide += (v & 15) << 2;
							else if (i < 0 && sigdata->flags & IT_WAS_A_669)
								channel->portamento += v << 3;
							else if (i < 0)
								channel->portamento += v << 4;
						}
					}
				}
				break;
			case IT_XM_PORTAMENTO_DOWN:
				{
					unsigned char v = entry->effectvalue;
					if (!(sigdata->flags & IT_WAS_A_MOD)) {
						if (v == 0)
							v = channel->lastJ;
						channel->lastJ = v;
					}
					if (channel->playing)
						channel->portamento -= v << 4;
				}
				break;
			case IT_XM_PORTAMENTO_UP:
				{
					unsigned char v = entry->effectvalue;
					if (!(sigdata->flags & IT_WAS_A_MOD)) {
						if (v == 0)
							v = channel->lastEF;
						channel->lastEF = v;
					}
					if (channel->playing)
						channel->portamento += v << 4;
				}
				break;
			case IT_XM_KEY_OFF:
				channel->key_off_count = entry->effectvalue;
				if (!channel->key_off_count) xm_note_off(sigdata, channel);
				break;
			case IT_VIBRATO:
				{
					if (entry->effectvalue || !(sigdata->flags & IT_WAS_A_669)) {
						unsigned char speed = entry->effectvalue >> 4;
						unsigned char depth = entry->effectvalue & 15;
						if (speed == 0)
							speed = channel->lastHspeed;
						channel->lastHspeed = speed;
						if (depth == 0)
							depth = channel->lastHdepth;
						else {
							if (sigdata->flags & IT_OLD_EFFECTS && !(sigdata->flags & IT_WAS_A_MOD))
								depth <<= 3;
							else
								depth <<= 2;
							channel->lastHdepth = depth;
						}
						for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) {
							if (i < 0) playing = channel->playing;
							else {
								playing = sigrenderer->playing[i];
								if (!playing || playing->channel != channel) continue;
							}
							if (playing) {
								playing->vibrato_speed = speed;
								playing->vibrato_depth = depth;
								playing->vibrato_n++;
							}
						}
					}
				}
				break;
			case IT_TREMOR:
				{
					unsigned char v = entry->effectvalue;
					if (v == 0) {
						if (sigdata->flags & IT_WAS_AN_S3M)
							v = channel->lastDKL;
						else
							v = channel->lastI;
					}
					else if (!(sigdata->flags & IT_OLD_EFFECTS)) {
						if (v & 0xF0) v -= 0x10;
						if (v & 0x0F) v -= 0x01;
					}
					if (sigdata->flags & IT_WAS_AN_S3M)
						channel->lastDKL = v;
					else
						channel->lastI = v;
					channel->tremor_time |= 128;
				}
				update_tremor(channel);
				break;
			case IT_ARPEGGIO:
				{
					unsigned char v = entry->effectvalue;
					/* XM files have no memory for arpeggio (000 = no effect)
					 * and we use lastJ for portamento down instead.
					 */
					if (!(sigdata->flags & IT_WAS_AN_XM)) {
						if (sigdata->flags & IT_WAS_AN_S3M) {
							if (v == 0)
								v = channel->lastDKL;
							channel->lastDKL = v;
						} else {
							if (v == 0)
								v = channel->lastJ;
							channel->lastJ = v;
						}
					}
					channel->arpeggio_offsets[0] = 0;
					channel->arpeggio_offsets[1] = (v & 0xF0) >> 4;
					channel->arpeggio_offsets[2] = (v & 0x0F);
					channel->arpeggio_table = (const unsigned char *)(((sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD))==IT_WAS_AN_XM) ? &arpeggio_xm : &arpeggio_mod);
				}
				break;
			case IT_SET_CHANNEL_VOLUME:
				if (sigdata->flags & IT_WAS_AN_XM)
					channel->volume = MIN(entry->effectvalue, 64);
				else if (entry->effectvalue <= 64)
					channel->channelvolume = entry->effectvalue;
#ifdef VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
				else
					channel->channelvolume = 64;
#endif
				if (channel->playing)
					channel->playing->channel_volume = channel->channelvolume;
				break;
			case IT_CHANNEL_VOLUME_SLIDE:
				{
					unsigned char v = entry->effectvalue;
					if (v == 0)
						v = channel->lastN;
					channel->lastN = v;
					if ((v & 0x0F) == 0) { /* Nx0 */
						channel->channelvolslide = v >> 4;
					} else if ((v & 0xF0) == 0) { /* N0x */
						channel->channelvolslide = -v;
					} else {
						if ((v & 0x0F) == 0x0F) { /* NxF */
							channel->channelvolume += v >> 4;
							if (channel->channelvolume > 64) channel->channelvolume = 64;
						} else if ((v & 0xF0) == 0xF0) { /* NFx */
							channel->channelvolume -= v & 15;
							if (channel->channelvolume > 64) channel->channelvolume = 0;
						} else
							break;
						if (channel->playing)
							channel->playing->channel_volume = channel->channelvolume;
					}
				}
				break;
			case IT_SET_SAMPLE_OFFSET:
				{
					unsigned char v = entry->effectvalue;
					/*if (sigdata->flags & IT_WAS_A_MOD) {
						if (v == 0) break;
					} else*/ {
						if (v == 0)
							v = channel->lastO;
						channel->lastO = v;
					}
					/* Note: we set the offset even if tone portamento is
					 * specified. Impulse Tracker does the same.
					 */
					if (entry->mask & IT_ENTRY_NOTE) {
						if (channel->playing) {
							int offset = ((int)channel->high_offset << 16) | ((int)v << 8);
							IT_PLAYING *playing = channel->playing;
							IT_SAMPLE *sample = playing->sample;
							int end;
							if ((sample->flags & IT_SAMPLE_SUS_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF))
								end = sample->sus_loop_end;
							else if (sample->flags & IT_SAMPLE_LOOP)
								end = sample->loop_end;
							else {
								end = sample->length;
								if ( sigdata->flags & IT_WAS_PROCESSED && end > 64 ) // XXX bah damn LPC and edge case modules
									end -= 64;
							}
							if ((sigdata->flags & IT_WAS_A_PTM) && (sample->flags & IT_SAMPLE_16BIT))
								offset >>= 1;
							if (offset < end) {
								it_playing_reset_resamplers(playing, offset);
								playing->declick_stage = 0;
							} else if (sigdata->flags & IT_OLD_EFFECTS) {
								it_playing_reset_resamplers(playing, end);
								playing->declick_stage = 0;
							}
						}
					}
				}
				break;
			case IT_PANNING_SLIDE:
				/** JULIEN: guess what? the docs are wrong! (how unusual ;)
				 * Pxy seems to memorize its previous value... and there
				 * might be other mistakes like that... (sigh!)
				 */
				/** ENTHEH: umm... but... the docs say that Pxy memorises its
				 * value... don't they? :o
				 */
				{
					unsigned char v = entry->effectvalue;
					int p = channel->truepan;
					if (sigdata->flags & IT_WAS_AN_XM)
					{
						if (IT_IS_SURROUND(channel->pan))
						{
							channel->pan = 32;
							p = 32 + 128 * 64;
						}
						p >>= 6;
					}
					else {
						if (IT_IS_SURROUND(channel->pan)) p = 32 << 8;
						p = (p + 128) >> 8;
						channel->pan = p;
					}
					if (v == 0)
						v = channel->lastP;
					channel->lastP = v;
					if ((v & 0x0F) == 0) { /* Px0 */
						channel->panslide = -(v >> 4);
					} else if ((v & 0xF0) == 0) { /* P0x */
						channel->panslide = v;
					} else if ((v & 0x0F) == 0x0F) { /* PxF */
						p -= v >> 4;
					} else if ((v & 0xF0) == 0xF0) { /* PFx */
						p += v & 15;
					}
					if (sigdata->flags & IT_WAS_AN_XM)
						channel->truepan = 32 + MID(0, p, 255) * 64;
					else {
						if (p < 0) p = 0;
						else if (p > 64) p = 64;
						channel->pan = p;
						channel->truepan = p << 8;
					}
				}
				break;
			case IT_RETRIGGER_NOTE:
				{
					unsigned char v = entry->effectvalue;
					if (sigdata->flags & IT_WAS_AN_XM) {
						if ((v & 0x0F) == 0) v |= channel->lastQ & 0x0F;
						if ((v & 0xF0) == 0) v |= channel->lastQ & 0xF0;
						channel->lastQ = v;
					} else if (sigdata->flags & IT_WAS_AN_S3M) {
						if (v == 0)
							v = channel->lastDKL;
						channel->lastDKL = v;
					} else {
						if (v == 0)
							v = channel->lastQ;
						channel->lastQ = v;
					}
					if ((v & 0x0F) == 0) v |= 0x01;
					channel->retrig = v;
					if (entry->mask & IT_ENTRY_NOTE) {
						channel->retrig_tick = v & 0x0F;
						/* Emulate a bug */
						if (sigdata->flags & IT_WAS_AN_XM)
							update_retrig(sigrenderer, channel);
					} else
						update_retrig(sigrenderer, channel);
				}
				break;
			case IT_XM_RETRIGGER_NOTE:
				channel->retrig_tick = channel->xm_retrig = entry->effectvalue;
				if (entry->effectvalue == 0)
					if (channel->playing) {
						it_playing_reset_resamplers(channel->playing, 0);
						channel->playing->declick_stage = 0;
					}
				break;
			case IT_TREMOLO:
				{
					unsigned char speed, depth;
					if (sigdata->flags & IT_WAS_AN_S3M) {
						unsigned char v = entry->effectvalue;
						if (v == 0)
							v = channel->lastDKL;
						channel->lastDKL = v;
						speed = v >> 4;
						depth = v & 15;
					} else {
						speed = entry->effectvalue >> 4;
						depth = entry->effectvalue & 15;
						if (speed == 0)
							speed = channel->lastRspeed;
						channel->lastRspeed = speed;
						if (depth == 0)
							depth = channel->lastRdepth;
						channel->lastRdepth = depth;
					}
					for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) {
						if (i < 0) playing = channel->playing;
						else {
							playing = sigrenderer->playing[i];
							if (!playing || playing->channel != channel) continue;
						}
						if (playing) {
							playing->tremolo_speed = speed;
							playing->tremolo_depth = depth;
						}
					}
				}
				break;
			case IT_S:
				{
					/* channel->lastS was set in update_pattern_variables(). */
					unsigned char effectvalue = channel->lastS;
					switch (effectvalue >> 4) {
						//case IT_S_SET_FILTER:
							/* Waveforms for commands S3x, S4x and S5x:
							 *   0: Sine wave
							 *   1: Ramp down
							 *   2: Square wave
							 *   3: Random wave
							 */
						case IT_S_SET_GLISSANDO_CONTROL:
							channel->glissando = effectvalue & 15;
							break;

						case IT_S_FINETUNE:
							if (channel->playing) {
								channel->playing->finetune = ((int)(effectvalue & 15) - 8) << 5;
							}
							break;

						case IT_S_SET_VIBRATO_WAVEFORM:
							{
								int waveform = effectvalue & 3;
								if (sigdata->flags & IT_WAS_A_MOD) waveform = mod_convert_vibrato[waveform];
								else if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform];
								channel->vibrato_waveform = waveform;
								if (channel->playing) {
									channel->playing->vibrato_waveform = waveform;
									if (!(effectvalue & 4))
										channel->playing->vibrato_time = 0;
								}
							}
							break;
						case IT_S_SET_TREMOLO_WAVEFORM:
							{
								int waveform = effectvalue & 3;
								if (sigdata->flags & IT_WAS_A_MOD) waveform = mod_convert_vibrato[waveform];
								else if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform];
								channel->tremolo_waveform = waveform;
								if (channel->playing) {
									channel->playing->tremolo_waveform = waveform;
									if (!(effectvalue & 4))
										channel->playing->tremolo_time = 0;
								}
							}
							break;
						case IT_S_SET_PANBRELLO_WAVEFORM:
							channel->panbrello_waveform = effectvalue & 3;
							if (channel->playing) {
								channel->playing->panbrello_waveform = effectvalue & 3;
								if (!(effectvalue & 4))
									channel->playing->panbrello_time = 0;
							}
							break;

						case IT_S_FINE_PATTERN_DELAY:
							sigrenderer->tick += effectvalue & 15;
							break;
#if 1
						case IT_S7:
							{
								if (sigrenderer->sigdata->flags & IT_USE_INSTRUMENTS)
								{
									int i;
									switch (effectvalue & 15)
									{
									case 0: /* cut background notes */
										for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++)
										{
											IT_PLAYING * playing = sigrenderer->playing[i];
											if (playing && channel == playing->channel)
											{
												playing->declick_stage = 3;
												if (channel->playing == playing) channel->playing = NULL;
											}
										}
										break;
									case 1: /* release background notes */
										for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++)
										{
											IT_PLAYING * playing = sigrenderer->playing[i];
											if (playing && channel == playing->channel && !(playing->flags & IT_PLAYING_SUSTAINOFF))
											{
												it_note_off(playing);
											}
										}
										break;
									case 2: /* fade background notes */
										for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++)
										{
											IT_PLAYING * playing = sigrenderer->playing[i];
											if (playing && channel == playing->channel)
											{
												//playing->flags &= IT_PLAYING_SUSTAINOFF;
												playing->flags |= IT_PLAYING_FADING;
											}
										}
										break;
									case 3:
										channel->new_note_action = NNA_NOTE_CUT;
										break;
									case 4:
										channel->new_note_action = NNA_NOTE_CONTINUE;
										break;
									case 5:
										channel->new_note_action = NNA_NOTE_OFF;
										break;
									case 6:
										channel->new_note_action = NNA_NOTE_FADE;
										break;

									case 7:
										if (channel->playing)
											channel->playing->enabled_envelopes &= ~IT_ENV_VOLUME;
										break;
									case 8:
										if (channel->playing)
											channel->playing->enabled_envelopes |= IT_ENV_VOLUME;
										break;

									case 9:
										if (channel->playing)
											channel->playing->enabled_envelopes &= ~IT_ENV_PANNING;
										break;
									case 10:
										if (channel->playing)
											channel->playing->enabled_envelopes |= IT_ENV_PANNING;
										break;

									case 11:
										if (channel->playing)
											channel->playing->enabled_envelopes &= ~IT_ENV_PITCH;
										break;
									case 12:
										if (channel->playing)
											channel->playing->enabled_envelopes |= IT_ENV_PITCH;
										break;
									}
								}
							}
							break;
#endif
						case IT_S_SET_PAN:
							//ASSERT(!(sigdata->flags & IT_WAS_AN_XM));
							channel->pan =
								((effectvalue & 15) << 2) |
								((effectvalue & 15) >> 2);
							channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;

							if (channel->playing)
								channel->playing->panbrello_depth = 0;
							break;
						case IT_S_SET_SURROUND_SOUND:
							if ((effectvalue & 15) == 15) {
								if (channel->playing && channel->playing->sample &&
									!(channel->playing->sample->flags & (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP))) {
									channel->playing->flags |= IT_PLAYING_REVERSE;
									it_playing_reset_resamplers( channel->playing, channel->playing->sample->length - 1 );
								}
							} else if ((effectvalue & 15) == 1) {
								channel->pan = IT_SURROUND;
								channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
							}
							if (channel->playing)
								channel->playing->panbrello_depth = 0;
							break;
						case IT_S_SET_HIGH_OFFSET:
							channel->high_offset = effectvalue & 15;
							break;
						//case IT_S_PATTERN_LOOP:
						case IT_S_DELAYED_NOTE_CUT:
							channel->note_cut_count = effectvalue & 15;
							if (!channel->note_cut_count) {
								if (sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_PTM))
									channel->volume = 0;
								else
									channel->note_cut_count = 1;
							}
							break;
						case IT_S_SET_MIDI_MACRO:
							if ((sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_MOD)) == (IT_WAS_AN_XM | IT_WAS_A_MOD)) {
								channel->inv_loop_speed = effectvalue & 15;
								update_invert_loop(channel, channel->playing ? channel->playing->sample : NULL);
							} else channel->SFmacro = effectvalue & 15;
							break;
					}
				}
				break;
			case IT_SET_SONG_TEMPO:
				{
					unsigned char v = entry->effectvalue;
					if (v == 0)
						v = channel->lastW;
					channel->lastW = v;
					if (v < 0x10)
						sigrenderer->temposlide = -v;
					else if (v < 0x20)
						sigrenderer->temposlide = v & 15;
					else
						sigrenderer->tempo = v;
				}
				break;
			case IT_FINE_VIBRATO:
				{
					unsigned char speed = entry->effectvalue >> 4;
					unsigned char depth = entry->effectvalue & 15;
					if (speed == 0)
						speed = channel->lastHspeed;
					channel->lastHspeed = speed;
					if (depth == 0)
						depth = channel->lastHdepth;
					else {
						if (sigdata->flags & IT_OLD_EFFECTS)
							depth <<= 1;
						channel->lastHdepth = depth;
					}
					for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) {
						if (i < 0) playing = channel->playing;
						else {
							playing = sigrenderer->playing[i];
							if (!playing || playing->channel != channel) continue;
						}
						if (playing) {
							playing->vibrato_speed = speed;
							playing->vibrato_depth = depth;
							playing->vibrato_n++;
						}
					}
				}
				break;
			case IT_SET_GLOBAL_VOLUME:
				if ((sigdata->flags & IT_WAS_AN_S3M) && (entry->effectvalue > 64))
					break;
				if (entry->effectvalue <= 128)
					sigrenderer->globalvolume = entry->effectvalue;
#ifdef VOLUME_OUT_OF_RANGE_SETS_MAXIMUM
				else
					sigrenderer->globalvolume = 128;
#endif
				break;
			case IT_GLOBAL_VOLUME_SLIDE:
				{
					unsigned char v = entry->effectvalue;
					if (v == 0)
						v = channel->lastW;
					channel->lastW = v;
					if ((v & 0x0F) == 0) { /* Wx0 */
						sigrenderer->globalvolslide =
							(sigdata->flags & IT_WAS_AN_XM) ? (v >> 4)*2 : (v >> 4);
					} else if ((v & 0xF0) == 0) { /* W0x */
						sigrenderer->globalvolslide =
							(sigdata->flags & IT_WAS_AN_XM) ? (-v)*2 : (-v);
					} else if ((v & 0x0F) == 0x0F) { /* WxF */
						sigrenderer->globalvolume += v >> 4;
						if (sigrenderer->globalvolume > 128) sigrenderer->globalvolume = 128;
					} else if ((v & 0xF0) == 0xF0) { /* WFx */
						sigrenderer->globalvolume -= v & 15;
						if (sigrenderer->globalvolume > 128) sigrenderer->globalvolume = 0;
					}
				}
				break;
			case IT_SET_PANNING:
				if (sigdata->flags & IT_WAS_AN_XM) {
					channel->truepan = 32 + entry->effectvalue*64;
				} else {
					if (sigdata->flags & IT_WAS_AN_S3M)
						channel->pan = (entry->effectvalue + 1) >> 1;
					else
						channel->pan = (entry->effectvalue + 2) >> 2;
					channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
				}
				if (channel->playing)
					channel->playing->panbrello_depth = 0;
				break;
			case IT_PANBRELLO:
				{
					unsigned char speed = entry->effectvalue >> 4;
					unsigned char depth = entry->effectvalue & 15;
					if (speed == 0)
						speed = channel->lastYspeed;
					channel->lastYspeed = speed;
					if (depth == 0)
						depth = channel->lastYdepth;
					channel->lastYdepth = depth;
					if (channel->playing) {
						channel->playing->panbrello_speed = speed;
						channel->playing->panbrello_depth = depth;
					}
				}
				break;
			case IT_MIDI_MACRO:
				{
					const IT_MIDI *midi = sigdata->midi ? sigdata->midi : &default_midi;
					if (entry->effectvalue >= 0x80) {
						int n = midi->Zmacrolen[entry->effectvalue-0x80];
						int i;
						for (i = 0; i < n; i++)
							it_send_midi(sigrenderer, channel, midi->Zmacro[entry->effectvalue-0x80][i]);
					} else {
						int n = midi->SFmacrolen[channel->SFmacro];
						int i, j;
						for (i = 0, j = 1; i < n; i++, j <<= 1)
							it_send_midi(sigrenderer, channel,
								(unsigned char)(midi->SFmacroz[channel->SFmacro] & j ?
									entry->effectvalue : midi->SFmacro[channel->SFmacro][i]));
					}
				}
				break;
			case IT_XM_SET_ENVELOPE_POSITION:
				if (channel->playing && channel->playing->env_instrument) {
					IT_ENVELOPE *envelope = &channel->playing->env_instrument->volume_envelope;
					if (envelope->flags & IT_ENVELOPE_ON) {
						IT_PLAYING_ENVELOPE *pe = &channel->playing->volume_envelope;
						pe->tick = entry->effectvalue;
						if (pe->tick >= envelope->node_t[envelope->n_nodes-1])
							pe->tick = envelope->node_t[envelope->n_nodes-1];
						pe->next_node = 0;
						while (pe->tick > envelope->node_t[pe->next_node]) pe->next_node++;
						xm_envelope_calculate_value(envelope, pe);
					}
				}
				break;

			/* uggly plain portamento for now */
			case IT_PTM_NOTE_SLIDE_DOWN:
			case IT_PTM_NOTE_SLIDE_DOWN_RETRIG:
				{
					channel->toneslide_retrig = (entry->effect == IT_PTM_NOTE_SLIDE_DOWN_RETRIG);

					if (channel->ptm_last_toneslide) {
						channel->toneslide_tick = channel->last_toneslide_tick;

						if (--channel->toneslide_tick == 0) {
							channel->truenote += channel->toneslide;
							if (channel->truenote >= 120) {
								if (channel->toneslide < 0) channel->truenote = 0;
								else channel->truenote = 119;
							}
							channel->note += channel->toneslide;
							if (channel->note >= 120) {
								if (channel->toneslide < 0) channel->note = 0;
								else channel->note = 119;
							}

							if (channel->playing) {
								if (channel->sample) channel->playing->note = channel->truenote;
								else channel->playing->note = channel->note;
								it_playing_reset_resamplers(channel->playing, 0);
								channel->playing->declick_stage = 0;
							}
						}
					}

					channel->ptm_last_toneslide = 0;

					channel->toneslide = -(entry->effectvalue & 15);
					channel->ptm_toneslide = (entry->effectvalue & 0xF0) >> 4;
					channel->toneslide_tick += channel->ptm_toneslide;
				}
				break;
			case IT_PTM_NOTE_SLIDE_UP:
			case IT_PTM_NOTE_SLIDE_UP_RETRIG:
				{
					channel->toneslide_retrig = (entry->effect == IT_PTM_NOTE_SLIDE_UP_RETRIG);

					if (channel->ptm_last_toneslide) {
						channel->toneslide_tick = channel->last_toneslide_tick;

						if (--channel->toneslide_tick == 0) {
							channel->truenote += channel->toneslide;
							if (channel->truenote >= 120) {
								if (channel->toneslide < 0) channel->truenote = 0;
								else channel->truenote = 119;
							}
							channel->note += channel->toneslide;
							if (channel->note >= 120) {
								if (channel->toneslide < 0) channel->note = 0;
								else channel->note = 119;
							}

							if (channel->playing) {
								if (channel->sample) channel->playing->note = channel->truenote;
								else channel->playing->note = channel->note;
								it_playing_reset_resamplers(channel->playing, 0);
								channel->playing->declick_stage = 0;
							}
						}
					}

					channel->ptm_last_toneslide = 0;

					channel->toneslide = -(entry->effectvalue & 15);
					channel->ptm_toneslide = (entry->effectvalue & 0xF0) >> 4;
					channel->toneslide_tick += channel->ptm_toneslide;
				}
				break;

			case IT_OKT_NOTE_SLIDE_DOWN:
			case IT_OKT_NOTE_SLIDE_DOWN_ROW:
				channel->toneslide = -entry->effectvalue;
				channel->okt_toneslide = (entry->effect == IT_OKT_NOTE_SLIDE_DOWN) ? 255 : 1;
				break;

			case IT_OKT_NOTE_SLIDE_UP:
			case IT_OKT_NOTE_SLIDE_UP_ROW:
				channel->toneslide = entry->effectvalue;
				channel->okt_toneslide = (entry->effect == IT_OKT_NOTE_SLIDE_UP) ? 255 : 1;
				break;

			case IT_OKT_ARPEGGIO_3:
			case IT_OKT_ARPEGGIO_4:
			case IT_OKT_ARPEGGIO_5:
				{
					channel->arpeggio_offsets[0] = 0;
					channel->arpeggio_offsets[1] = -(entry->effectvalue >> 4);
					channel->arpeggio_offsets[2] = entry->effectvalue & 0x0F;

					switch (entry->effect)
					{
					case IT_OKT_ARPEGGIO_3:
						channel->arpeggio_table = (const unsigned char *)&arpeggio_okt_3;
						break;

					case IT_OKT_ARPEGGIO_4:
						channel->arpeggio_table = (const unsigned char *)&arpeggio_okt_4;
						break;

					case IT_OKT_ARPEGGIO_5:
						channel->arpeggio_table = (const unsigned char *)&arpeggio_okt_5;
						break;
					}
				}
				break;

			case IT_OKT_VOLUME_SLIDE_DOWN:
				if ( entry->effectvalue <= 16 ) channel->volslide = -entry->effectvalue;
				else
				{
					channel->volume -= entry->effectvalue - 16;
					if (channel->volume > 64) channel->volume = 0;
				}
				break;

			case IT_OKT_VOLUME_SLIDE_UP:
				if ( entry->effectvalue <= 16 ) channel->volslide = entry->effectvalue;
				else
				{
					channel->volume += entry->effectvalue - 16;
					if (channel->volume > 64) channel->volume = 64;
				}
				break;
		}
	}

	if (!(sigdata->flags & IT_WAS_AN_XM))
		post_process_it_volpan(sigrenderer, entry);

	return 0;
}