static void process_xm_note_data()

in doom_py/src/vizdoom/dumb/src/it/itrender.c [3330:3620]


static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry)
{
	DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
	IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];
	IT_PLAYING * playing = NULL;

	if (entry->mask & IT_ENTRY_INSTRUMENT) {
		int oldsample = channel->sample;
		channel->inv_loop_offset = 0;
		channel->instrument = entry->instrument;
		instrument_to_sample(sigdata, channel);
		if (channel->playing &&
			!((entry->mask & IT_ENTRY_NOTE) && entry->note >= 120) &&
			!((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_XM_KEY_OFF && entry->effectvalue == 0)) {
			playing = dup_playing(channel->playing, channel, channel);
			if (!playing) return;
			if (!(sigdata->flags & IT_WAS_A_MOD)) {
				/* Retrigger vol/pan envelopes if enabled, and cancel fadeout.
				 * Also reset vol/pan to that of _original_ instrument.
				 */
				channel->playing->flags &= ~(IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING);
				it_playing_update_resamplers(channel->playing);

				channel->volume = channel->playing->sample->default_volume;
				channel->truepan = 32 + channel->playing->sample->default_pan*64;

				retrigger_xm_envelopes(channel->playing);
			} else {
				/* Switch if sample changed */
				if (oldsample != channel->sample) {
					int i;
					for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
						if (!sigrenderer->playing[i]) {
							channel->playing->declick_stage = 3;
							sigrenderer->playing[i] = channel->playing;
							channel->playing = NULL;
							break;
						}
					}

					if (!channel->sample) {
						if (channel->playing)
						{
							free_playing(sigrenderer, channel->playing);
							channel->playing = NULL;
						}
					} else {
						if (channel->playing) {
							free_playing(sigrenderer, channel->playing);
						}
						channel->playing = playing;
						playing = NULL;
						channel->playing->declick_stage = 0;
						channel->playing->sampnum = channel->sample;
						channel->playing->sample = &sigdata->sample[channel->sample-1];
						it_playing_reset_resamplers(channel->playing, 0);
					}
				}
				get_default_volpan(sigdata, channel);
			}
		}
	}

	if (!((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_XM_KEY_OFF && entry->effectvalue == 0) &&
		(entry->mask & IT_ENTRY_NOTE))
	{
		if (!(entry->mask & IT_ENTRY_INSTRUMENT))
			instrument_to_sample(sigdata, channel);

		if (channel->note >= 120)
			xm_note_off(sigdata, channel);
		else if (channel->sample == 0) {
			/** If we get here, one of the following is the case:
			 ** 1. The instrument has never been specified on this channel.
			 ** 2. The specified instrument is invalid.
			 ** 3. The instrument has no sample mapped to the selected note.
			 ** What should happen?
			 **
			 ** Experimentation shows that any existing note stops and cannot
			 ** be brought back. A subsequent instrument change fixes that.
			 **/
			if (channel->playing) {
				int i;
				if (playing) {
					free_playing(sigrenderer, channel->playing);
					channel->playing = playing;
					playing = NULL;
				}
				for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
					if (!sigrenderer->playing[i]) {
						channel->playing->declick_stage = 3;
						sigrenderer->playing[i] = channel->playing;
						channel->playing = NULL;
						break;
					}
				}
				if (channel->playing) {
					free_playing(sigrenderer, channel->playing);
					channel->playing = NULL;
				}
			}
			if (playing) free_playing(sigrenderer, playing);
			return;
		} else if (channel->playing && (entry->mask & IT_ENTRY_VOLPAN) && ((entry->volpan>>4) == 0xF)) {
			/* Don't retrigger note; portamento in the volume column. */
		} else if (channel->playing &&
		           (entry->mask & IT_ENTRY_EFFECT) &&
		           (entry->effect == IT_TONE_PORTAMENTO ||
		            entry->effect == IT_VOLSLIDE_TONEPORTA)) {
			/* Don't retrigger note; portamento in the effects column. */
		} else {
			channel->destnote = IT_NOTE_OFF;

			if (!channel->playing) {
				channel->playing = new_playing(sigrenderer);
				if (!channel->playing) {
					if (playing) free_playing(sigrenderer, playing);
					return;
				}
				// Adding the following seems to do the trick for the case where a piece starts with an instrument alone and then some notes alone.
				retrigger_xm_envelopes(channel->playing);
			}
			else if (playing) {
				/* volume rampy stuff! move note to NNA */
				int i;
				IT_PLAYING * ptemp;
				if (playing->sample) ptemp = playing;
				else ptemp = channel->playing;
				if (!ptemp) {
					if (playing) free_playing(sigrenderer, playing);
					return;
				}
				playing = NULL;
				for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
					if (!sigrenderer->playing[i]) {
						ptemp->declick_stage = 3;
						ptemp->flags |= IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING;
						sigrenderer->playing[i] = ptemp;
						ptemp = NULL;
						break;
					}
				}
				if (ptemp) free_playing(sigrenderer, ptemp);
			}

			channel->playing->flags = 0;
			channel->playing->resampling_quality = sigrenderer->resampling_quality;
			channel->playing->channel = channel;
			channel->playing->sample = &sigdata->sample[channel->sample-1];
			if (sigdata->flags & IT_USE_INSTRUMENTS)
				channel->playing->instrument = &sigdata->instrument[channel->instrument-1];
			else
				channel->playing->instrument = NULL;
			channel->playing->env_instrument = channel->playing->instrument;
			channel->playing->sampnum = channel->sample;
			channel->playing->instnum = channel->instrument;
			channel->playing->declick_stage = 0;
			channel->playing->channel_volume = channel->channelvolume;
			channel->playing->note = channel->truenote;
			channel->playing->enabled_envelopes = 0;
			channel->playing->volume_offset = 0;
			channel->playing->panning_offset = 0;
			//channel->playing->output = channel->output;
			if (sigdata->flags & IT_USE_INSTRUMENTS) {
				IT_PLAYING * playing = channel->playing;
				IT_INSTRUMENT * instrument = playing->instrument;
				if (instrument->volume_envelope.flags & IT_ENVELOPE_ON) playing->enabled_envelopes |= IT_ENV_VOLUME;
				if (instrument->pan_envelope.flags & IT_ENVELOPE_ON) playing->enabled_envelopes |= IT_ENV_PANNING;
				//if (instrument->output) playing->output = instrument->output;
			}
			channel->playing->filter_cutoff = 127;
			channel->playing->filter_resonance = 0;
			channel->playing->true_filter_cutoff = 127 << 8;
			channel->playing->true_filter_resonance = 0;
			channel->playing->vibrato_speed = 0;
			channel->playing->vibrato_depth = 0;
			channel->playing->vibrato_n = 0;
			channel->playing->vibrato_time = 0;
			channel->playing->vibrato_waveform = 0;
			channel->playing->tremolo_speed = 0;
			channel->playing->tremolo_depth = 0;
			channel->playing->tremolo_time = 0;
			channel->playing->tremolo_waveform = 0;
			channel->playing->panbrello_speed = 0;
			channel->playing->panbrello_depth = 0;
			channel->playing->panbrello_time = 0;
			channel->playing->panbrello_waveform = 0;
			channel->playing->panbrello_random = 0;
			channel->playing->sample_vibrato_time = 0;
			channel->playing->sample_vibrato_waveform = channel->playing->sample->vibrato_waveform;
			channel->playing->sample_vibrato_depth = 0;
			channel->playing->slide = 0;
			channel->playing->finetune = channel->playing->sample->finetune;
			it_reset_filter_state(&channel->playing->filter_state[0]); // Are these
			it_reset_filter_state(&channel->playing->filter_state[1]); // necessary?
			it_playing_reset_resamplers(channel->playing, 0);

			/** WARNING - is everything initialised? */
		}
	}

	if (!((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_XM_KEY_OFF && entry->effectvalue == 0) &&
		!((entry->mask & IT_ENTRY_NOTE) && entry->note >= 120) &&
		(entry->mask & (IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT)) == (IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT))
	{
		if (channel->playing) retrigger_xm_envelopes(channel->playing);
		get_default_volpan(sigdata, channel);
	}

	if ((entry->mask & IT_ENTRY_VOLPAN) && ((entry->volpan>>4) == 0xF)) {
		/* Tone Portamento */
		unsigned char v = (entry->volpan & 15) << 4;
		if (v == 0)
			v = channel->lastG;
		channel->lastG = v;
		if (entry->mask & IT_ENTRY_NOTE)
			if (channel->sample && channel->note < 120)
				channel->destnote = channel->truenote;
		channel->toneporta = v << 4;
	} else if ((entry->mask & IT_ENTRY_EFFECT) &&
	           (entry->effect == IT_TONE_PORTAMENTO ||
	            entry->effect == IT_VOLSLIDE_TONEPORTA)) {
		unsigned char v;
		if (entry->effect == IT_TONE_PORTAMENTO)
			v = entry->effectvalue;
		else
			v = 0;
		if (v == 0)
			v = channel->lastG;
		channel->lastG = v;
		if (entry->mask & IT_ENTRY_NOTE)
			if (channel->sample && channel->note < 120)
				channel->destnote = channel->truenote;
		channel->toneporta = v << 4;
	}

	if (entry->mask & IT_ENTRY_VOLPAN) {
		int effect = entry->volpan >> 4;
		int value  = entry->volpan & 15;
		switch (effect) {
			case 0x6: /* Volume slide down */
				channel->xm_volslide = -value;
				break;
			case 0x7: /* Volume slide up */
				channel->xm_volslide = value;
				break;
			case 0x8: /* Fine volume slide down */
				channel->volume -= value;
				if (channel->volume > 64) channel->volume = 0;
				break;
			case 0x9: /* Fine volume slide up */
				channel->volume += value;
				if (channel->volume > 64) channel->volume = 64;
				break;
			case 0xA: /* Set vibrato speed */
				if (value)
					channel->lastHspeed = value;
				if (channel->playing)
					channel->playing->vibrato_speed = channel->lastHspeed;
				break;
			case 0xB: /* Vibrato */
				if (value)
					channel->lastHdepth = value << 2; /** WARNING: correct ? */
				if (channel->playing) {
					channel->playing->vibrato_depth = channel->lastHdepth;
					channel->playing->vibrato_speed = channel->lastHspeed;
					channel->playing->vibrato_n++;
				}
				break;
			case 0xC: /* Set panning */
				channel->truepan = 32 + value*(17*64);
				break;
			case 0xD: /* Pan slide left */
				/* -128 is a special case for emulating a 'feature' in FT2.
				 * As soon as effects are processed, it goes hard left.
				 */
				channel->panslide = value ? -value : -128;
				break;
			case 0xE: /* Pan slide Right */
				channel->panslide = value;
				break;
			case 0xF: /* Tone porta */
				break;
			default:  /* Volume */
				channel->volume = entry->volpan - 0x10;
				break;
		}
	}

	if (playing) free_playing(sigrenderer, playing);
}