summaryrefslogtreecommitdiff
path: root/plugins/dumb/dumb-kode54/src/it/itrender.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/dumb/dumb-kode54/src/it/itrender.c')
-rw-r--r--plugins/dumb/dumb-kode54/src/it/itrender.c5542
1 files changed, 5542 insertions, 0 deletions
diff --git a/plugins/dumb/dumb-kode54/src/it/itrender.c b/plugins/dumb/dumb-kode54/src/it/itrender.c
new file mode 100644
index 00000000..5dd8e4ef
--- /dev/null
+++ b/plugins/dumb/dumb-kode54/src/it/itrender.c
@@ -0,0 +1,5542 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * itrender.c - Code to render an Impulse Tracker / / \ \
+ * module. | < / \_
+ * | \/ /\ /
+ * Written - painstakingly - by entheh. \_ / > /
+ * | \ / /
+ * | ' /
+ * \__/
+ */
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "dumb.h"
+#include "internal/dumb.h"
+#include "internal/it.h"
+
+// #define BIT_ARRAY_BULLSHIT
+
+#define END_RAMPING
+#define RAMP_DOWN
+
+static IT_PLAYING *dup_playing(IT_PLAYING *src, IT_CHANNEL *dstchannel, IT_CHANNEL *srcchannel)
+{
+ IT_PLAYING *dst;
+
+ if (!src) return NULL;
+
+ dst = malloc(sizeof(*dst));
+ if (!dst) return NULL;
+
+ dst->flags = src->flags;
+ dst->resampling_quality = src->resampling_quality;
+
+ ASSERT(src->channel);
+ dst->channel = &dstchannel[src->channel - srcchannel];
+ dst->sample = src->sample;
+ dst->instrument = src->instrument;
+ dst->env_instrument = src->env_instrument;
+
+ dst->sampnum = src->sampnum;
+ dst->instnum = src->instnum;
+
+#ifdef END_RAMPING
+ dst->declick_stage = src->declick_stage;
+ dst->declick_volume = src->declick_volume;
+#endif
+
+ dst->float_volume[0] = src->float_volume[0];
+ dst->float_volume[1] = src->float_volume[1];
+
+ dst->ramp_volume[0] = src->ramp_volume[0];
+ dst->ramp_volume[1] = src->ramp_volume[1];
+
+ dst->ramp_delta[0] = src->ramp_delta[0];
+ dst->ramp_delta[1] = src->ramp_delta[1];
+
+ dst->channel_volume = src->channel_volume;
+
+ dst->volume = src->volume;
+ dst->pan = src->pan;
+
+ dst->volume_offset = src->volume_offset;
+ dst->panning_offset = src->panning_offset;
+
+ dst->note = src->note;
+
+ dst->enabled_envelopes = src->enabled_envelopes;
+
+ dst->filter_cutoff = src->filter_cutoff;
+ dst->filter_resonance = src->filter_resonance;
+
+ dst->true_filter_cutoff = src->true_filter_cutoff;
+ dst->true_filter_resonance = src->true_filter_resonance;
+
+ dst->vibrato_speed = src->vibrato_speed;
+ dst->vibrato_depth = src->vibrato_depth;
+ dst->vibrato_n = src->vibrato_n;
+ dst->vibrato_time = src->vibrato_time;
+ dst->vibrato_waveform = src->vibrato_waveform;
+
+ dst->tremolo_speed = src->tremolo_speed;
+ dst->tremolo_depth = src->tremolo_depth;
+ dst->tremolo_time = src->tremolo_time;
+ dst->tremolo_waveform = src->tremolo_waveform;
+
+ dst->panbrello_speed = src->panbrello_speed;
+ dst->panbrello_depth = src->panbrello_depth;
+ dst->panbrello_time = src->panbrello_time;
+ dst->panbrello_waveform = src->panbrello_waveform;
+ dst->panbrello_random = src->panbrello_random;
+
+ dst->sample_vibrato_time = src->sample_vibrato_time;
+ dst->sample_vibrato_waveform = src->sample_vibrato_waveform;
+ dst->sample_vibrato_depth = src->sample_vibrato_depth;
+
+ dst->slide = src->slide;
+ dst->delta = src->delta;
+ dst->finetune = src->finetune;
+
+ dst->volume_envelope = src->volume_envelope;
+ dst->pan_envelope = src->pan_envelope;
+ dst->pitch_envelope = src->pitch_envelope;
+
+ dst->fadeoutcount = src->fadeoutcount;
+
+ dst->filter_state[0] = src->filter_state[0];
+ dst->filter_state[1] = src->filter_state[1];
+
+ dst->resampler = src->resampler;
+ dst->resampler.pickup_data = dst;
+ dst->time_lost = src->time_lost;
+
+ //dst->output = src->output;
+
+ return dst;
+}
+
+
+
+static void dup_channel(IT_CHANNEL *dst, IT_CHANNEL *src)
+{
+ dst->flags = src->flags;
+
+ dst->volume = src->volume;
+ dst->volslide = src->volslide;
+ dst->xm_volslide = src->xm_volslide;
+ dst->panslide = src->panslide;
+
+ dst->pan = src->pan;
+ dst->truepan = src->truepan;
+
+ dst->channelvolume = src->channelvolume;
+ dst->channelvolslide = src->channelvolslide;
+
+ dst->instrument = src->instrument;
+ dst->note = src->note;
+
+ dst->SFmacro = src->SFmacro;
+
+ dst->filter_cutoff = src->filter_cutoff;
+ dst->filter_resonance = src->filter_resonance;
+
+ dst->key_off_count = src->key_off_count;
+ dst->note_cut_count = src->note_cut_count;
+ dst->note_delay_count = src->note_delay_count;
+ dst->note_delay_entry = src->note_delay_entry;
+
+ dst->new_note_action = src->new_note_action;
+
+ dst->arpeggio = src->arpeggio;
+ dst->retrig = src->retrig;
+ dst->xm_retrig = src->xm_retrig;
+ dst->retrig_tick = src->retrig_tick;
+
+ dst->tremor_time = src->tremor_time;
+
+ dst->vibrato_waveform = src->vibrato_waveform;
+ dst->tremolo_waveform = src->tremolo_waveform;
+ dst->panbrello_waveform = src->panbrello_waveform;
+
+ dst->portamento = src->portamento;
+ dst->toneporta = src->toneporta;
+ dst->toneslide = src->toneslide;
+ dst->toneslide_tick = src->toneslide_tick;
+ dst->last_toneslide_tick = src->last_toneslide_tick;
+ dst->ptm_toneslide = src->ptm_toneslide;
+ dst->ptm_last_toneslide = src->ptm_last_toneslide;
+ dst->destnote = src->destnote;
+
+ dst->glissando = src->glissando;
+
+ dst->sample = src->sample;
+ dst->truenote = src->truenote;
+
+ dst->midi_state = src->midi_state;
+
+ dst->lastvolslide = src->lastvolslide;
+ dst->lastDKL = src->lastDKL;
+ dst->lastEF = src->lastEF;
+ dst->lastG = src->lastG;
+ dst->lastHspeed = src->lastHspeed;
+ dst->lastHdepth = src->lastHdepth;
+ dst->lastRspeed = src->lastRspeed;
+ dst->lastRdepth = src->lastRdepth;
+ dst->lastYspeed = src->lastYspeed;
+ dst->lastYdepth = src->lastYdepth;
+ dst->lastI = src->lastI;
+ dst->lastJ = src->lastJ;
+ dst->lastN = src->lastN;
+ dst->lastO = src->lastO;
+ dst->high_offset = src->high_offset;
+ dst->lastP = src->lastP;
+ dst->lastQ = src->lastQ;
+ dst->lastS = src->lastS;
+ dst->pat_loop_row = src->pat_loop_row;
+ dst->pat_loop_count = src->pat_loop_count;
+ dst->pat_loop_end_row = src->pat_loop_end_row;
+ dst->lastW = src->lastW;
+
+ dst->xm_lastE1 = src->xm_lastE1;
+ dst->xm_lastE2 = src->xm_lastE2;
+ dst->xm_lastEA = src->xm_lastEA;
+ dst->xm_lastEB = src->xm_lastEB;
+ dst->xm_lastX1 = src->xm_lastX1;
+ dst->xm_lastX2 = src->xm_lastX2;
+
+ dst->playing = dup_playing(src->playing, dst, src);
+
+
+#ifdef BIT_ARRAY_BULLSHIT
+ dst->played_patjump = bit_array_dup(src->played_patjump);
+ dst->played_patjump_order = src->played_patjump_order;
+#endif
+
+ //dst->output = src->output;
+}
+
+
+
+/* Allocate the new callbacks first, then pass them to this function!
+ * It will free them on failure.
+ */
+static DUMB_IT_SIGRENDERER *dup_sigrenderer(DUMB_IT_SIGRENDERER *src, int n_channels, IT_CALLBACKS *callbacks)
+{
+ DUMB_IT_SIGRENDERER *dst;
+ int i;
+
+ if (!src) {
+ if (callbacks) free(callbacks);
+ return NULL;
+ }
+
+ dst = malloc(sizeof(*dst));
+ if (!dst) {
+ if (callbacks) free(callbacks);
+ return NULL;
+ }
+
+ dst->sigdata = src->sigdata;
+
+ dst->n_channels = n_channels;
+
+ dst->resampling_quality = src->resampling_quality;
+
+ dst->globalvolume = src->globalvolume;
+ dst->globalvolslide = src->globalvolslide;
+
+ dst->tempo = src->tempo;
+ dst->temposlide = src->temposlide;
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++)
+ dup_channel(&dst->channel[i], &src->channel[i]);
+
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++)
+ dst->playing[i] = dup_playing(src->playing[i], dst->channel, src->channel);
+
+ dst->tick = src->tick;
+ dst->speed = src->speed;
+ dst->rowcount = src->rowcount;
+
+ dst->order = src->order;
+ dst->row = src->row;
+ dst->processorder = src->processorder;
+ dst->processrow = src->processrow;
+ dst->breakrow = src->breakrow;
+
+ dst->restart_position = src->restart_position;
+
+ dst->n_rows = src->n_rows;
+
+ dst->entry_start = src->entry_start;
+ dst->entry = src->entry;
+ dst->entry_end = src->entry_end;
+
+ dst->time_left = src->time_left;
+ dst->sub_time_left = src->sub_time_left;
+
+ dst->click_remover = NULL;
+
+ dst->callbacks = callbacks;
+
+#ifdef BIT_ARRAY_BULLSHIT
+ dst->played = bit_array_dup(src->played);
+#endif
+
+ dst->gvz_time = src->gvz_time;
+ dst->gvz_sub_time = src->gvz_sub_time;
+
+ //dst->max_output = src->max_output;
+
+ return dst;
+}
+
+
+
+static const IT_MIDI default_midi = {
+ /* unsigned char SFmacro[16][16]; */
+ {
+ {0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+ },
+ /* unsigned char SFmacrolen[16]; */
+ {4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* unsigned short SFmacroz[16]; */
+ /* Bitfield; bit 0 set = z in first position */
+ {
+ 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+ },
+ /* unsigned char Zmacro[128][16]; */
+ {
+ {0xF0, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0xF0, 0xF0, 0x01, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+ },
+ /* unsigned char Zmacrolen[128]; */
+ {
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ }
+};
+
+
+
+static void it_reset_filter_state(IT_FILTER_STATE *state)
+{
+ state->currsample = 0;
+ state->prevsample = 0;
+}
+
+
+
+#if 1
+#define LOG10 2.30258509299
+
+/* IMPORTANT: This function expects one extra sample in 'src' so it can apply
+ * click removal. It reads size samples, starting from src[0], and writes its
+ * output starting at dst[pos]. The pos parameter is required for getting
+ * click removal right.
+ */
+
+static void it_filter(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, long pos, sample_t *src, long size, int step, int sampfreq, int cutoff, int resonance)
+{
+ sample_t currsample = state->currsample;
+ sample_t prevsample = state->prevsample;
+
+ float a, b, c;
+
+ long datasize;
+
+ {
+ float inv_angle = (float)(sampfreq * pow(0.5, 0.25 + cutoff*(1.0/(24<<IT_ENVELOPE_SHIFT))) * (1.0/(2*3.14159265358979323846*110.0)));
+ float loss = (float)exp(resonance*(-LOG10*1.2/128.0));
+ float d, e;
+#if 0
+ loss *= 2; // This is the mistake most players seem to make!
+#endif
+
+#if 1
+ d = (1.0f - loss) / inv_angle;
+ if (d > 2.0f) d = 2.0f;
+ d = (loss - d) * inv_angle;
+ e = inv_angle * inv_angle;
+ a = 1.0f / (1.0f + d + e);
+ c = -e * a;
+ b = 1.0f - a - c;
+#else
+ a = 1.0f / (inv_angle*inv_angle + inv_angle*loss + loss);
+ c = -(inv_angle*inv_angle) * a;
+ b = 1.0f - a - c;
+#endif
+ }
+
+ dst += pos * step;
+ datasize = size * step;
+
+#define INT_FILTERS
+#ifdef INT_FILTERS
+#define MULSCA(a, b) ((int)((LONG_LONG)((a) << 4) * (b) >> 32))
+#define SCALEB 12
+ {
+ int ai = (int)(a * (1 << (16+SCALEB)));
+ int bi = (int)(b * (1 << (16+SCALEB)));
+ int ci = (int)(c * (1 << (16+SCALEB)));
+ int i;
+
+ if (cr) {
+ sample_t startstep = MULSCA(src[0], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci);
+ dumb_record_click(cr, pos, startstep);
+ }
+
+ for (i = 0; i < datasize; i += step) {
+ {
+ sample_t newsample = MULSCA(src[i], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci);
+ prevsample = currsample;
+ currsample = newsample;
+ }
+ dst[i] += currsample;
+ }
+
+ if (cr) {
+ sample_t endstep = MULSCA(src[datasize], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci);
+ dumb_record_click(cr, pos + size, -endstep);
+ }
+ }
+#else
+#error This version is broken - it does not use step, and state should contain floats for it
+ if (cr) {
+ float startstep = src[0]*a + currsample*b + prevsample*c;
+ dumb_record_click(cr, pos, (sample_t)startstep);
+ }
+
+ {
+ int i = size % 3;
+ while (i > 0) {
+ {
+ float newsample = *src++*a + currsample*b + prevsample*c;
+ prevsample = currsample;
+ currsample = newsample;
+ }
+ *dst++ += (sample_t)currsample;
+ i--;
+ }
+ i = size / 3;
+ while (i > 0) {
+ float newsample;
+ /* Gotta love unrolled loops! */
+ *dst++ += (sample_t)(newsample = *src++*a + currsample*b + prevsample*c);
+ *dst++ += (sample_t)(prevsample = *src++*a + newsample*b + currsample*c);
+ *dst++ += (sample_t)(currsample = *src++*a + prevsample*b + newsample*c);
+ i--;
+ }
+ }
+
+ if (cr) {
+ float endstep = src[datasize]*a + currsample*b + prevsample*c;
+ dumb_record_click(cr, pos + size, -(sample_t)endstep);
+ }
+#endif
+
+ state->currsample = currsample;
+ state->prevsample = prevsample;
+}
+#undef LOG10
+#endif
+
+
+
+static const signed char it_sine[256] = {
+ 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23,
+ 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
+ 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60,
+ 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46,
+ 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26,
+ 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2,
+ 0, -2, -3, -5, -6, -8, -9,-11,-12,-14,-16,-17,-19,-20,-22,-23,
+ -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44,
+ -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59,
+ -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64,
+ -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60,
+ -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,
+ -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26,
+ -24,-23,-22,-20,-19,-17,-16,-14,-12,-11, -9, -8, -6, -5, -3, -2
+};
+
+
+
+#if 1
+/** WARNING: use these! */
+/** JULIEN: Plus for XM compatibility it could be interesting to rename
+ * it_sawtooth[] to it_rampdown[], and add an it_rampup[].
+ * Also, still for XM compat', twood be good if it was possible to tell the
+ * the player not to retrig' the waveform on a new instrument.
+ * Both of these are only for completness though, as I don't think it would
+ * be very noticeable ;)
+ */
+/** ENTHEH: IT also has the 'don't retrig' thingy :) */
+static const signed char it_sawtooth[256] = {
+ 64, 63, 63, 62, 62, 61, 61, 60, 60, 59, 59, 58, 58, 57, 57, 56,
+ 56, 55, 55, 54, 54, 53, 53, 52, 52, 51, 51, 50, 50, 49, 49, 48,
+ 48, 47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 40,
+ 40, 39, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 32,
+ 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, 26, 25, 25, 24,
+ 24, 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16,
+ 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8,
+ 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0,
+ 0, -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6, -7, -7, -8,
+ -8, -9, -9,-10,-10,-11,-11,-12,-12,-13,-13,-14,-14,-15,-15,-16,
+ -16,-17,-17,-18,-18,-19,-19,-20,-20,-21,-21,-22,-22,-23,-23,-24,
+ -24,-25,-25,-26,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32,
+ -32,-33,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40,
+ -40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-46,-47,-47,-48,
+ -48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-54,-54,-55,-55,-56,
+ -56,-57,-57,-58,-58,-59,-59,-60,-60,-61,-61,-62,-62,-63,-63,-64
+};
+
+static const signed char it_squarewave[256] = {
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const signed char it_xm_ramp[256] = {
+ 0, -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6, -7, -7, -8,
+ -8, -9, -9,-10,-10,-11,-11,-12,-12,-13,-13,-14,-14,-15,-15,-16,
+ -16,-17,-17,-18,-18,-19,-19,-20,-20,-21,-21,-22,-22,-23,-23,-24,
+ -24,-25,-25,-26,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32,
+ -32,-33,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40,
+ -40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-46,-47,-47,-48,
+ -48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-54,-54,-55,-55,-56,
+ -56,-57,-57,-58,-58,-59,-59,-60,-60,-61,-61,-62,-62,-63,-63,-64,
+ 64, 63, 63, 62, 62, 61, 61, 60, 60, 59, 59, 58, 58, 57, 57, 56,
+ 56, 55, 55, 54, 54, 53, 53, 52, 52, 51, 51, 50, 50, 49, 49, 48,
+ 48, 47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 40,
+ 40, 39, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 32,
+ 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, 26, 25, 25, 24,
+ 24, 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16,
+ 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8,
+ 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0
+};
+
+static const signed char it_xm_squarewave[256] = {
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,
+ -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,
+ -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,
+ -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,
+ -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,
+ -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,
+ -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,
+ -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64
+};
+
+#endif
+
+
+
+static void reset_tick_counts(DUMB_IT_SIGRENDERER *sigrenderer)
+{
+ int i;
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ IT_CHANNEL *channel = &sigrenderer->channel[i];
+ channel->key_off_count = 0;
+ channel->note_cut_count = 0;
+ channel->note_delay_count = 0;
+ }
+}
+
+
+
+static void reset_channel_effects(IT_CHANNEL *channel)
+{
+ channel->volslide = 0;
+ channel->xm_volslide = 0;
+ channel->panslide = 0;
+ channel->channelvolslide = 0;
+ channel->arpeggio = 0;
+ channel->retrig = 0;
+ if (channel->xm_retrig) {
+ channel->xm_retrig = 0;
+ channel->retrig_tick = 0;
+ }
+ channel->tremor_time &= 127;
+ channel->portamento = 0;
+ channel->toneporta = 0;
+ if (channel->ptm_toneslide) {
+ channel->ptm_last_toneslide = channel->ptm_toneslide;
+ channel->last_toneslide_tick = channel->toneslide_tick;
+ } else
+ channel->ptm_last_toneslide = 0;
+ channel->ptm_toneslide = 0;
+ channel->toneslide_tick = 0;
+ if (channel->playing) {
+ channel->playing->vibrato_n = 0;
+ channel->playing->tremolo_speed = 0;
+ channel->playing->tremolo_depth = 0;
+ channel->playing->panbrello_speed = 0;
+ }
+}
+
+static void reset_effects(DUMB_IT_SIGRENDERER *sigrenderer)
+{
+ int i;
+
+ sigrenderer->globalvolslide = 0;
+ sigrenderer->temposlide = 0;
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ reset_channel_effects(&sigrenderer->channel[i]);
+ }
+}
+
+
+
+static void update_tremor(IT_CHANNEL *channel)
+{
+ if ((channel->tremor_time & 128) && channel->playing) {
+ if (channel->tremor_time == 128)
+ channel->tremor_time = (channel->lastI >> 4) | 192;
+ else if (channel->tremor_time == 192)
+ channel->tremor_time = (channel->lastI & 15) | 128;
+ else
+ channel->tremor_time--;
+ }
+}
+
+
+
+static void it_pickup_loop(DUMB_RESAMPLER *resampler, void *data)
+{
+ resampler->pos -= resampler->end - resampler->start;
+ ((IT_PLAYING *)data)->time_lost += resampler->end - resampler->start;
+}
+
+
+
+static void it_pickup_pingpong_loop(DUMB_RESAMPLER *resampler, void *data)
+{
+ if (resampler->dir < 0) {
+ resampler->pos = (resampler->start << 1) - 1 - resampler->pos;
+ resampler->subpos ^= 65535;
+ resampler->dir = 1;
+ ((IT_PLAYING *)data)->time_lost += (resampler->end - resampler->start) << 1;
+ } else {
+ resampler->pos = (resampler->end << 1) - 1 - resampler->pos;
+ resampler->subpos ^= 65535;
+ resampler->dir = -1;
+ }
+}
+
+
+
+static void it_pickup_stop_at_end(DUMB_RESAMPLER *resampler, void *data)
+{
+ (void)data;
+
+ if (resampler->dir < 0) {
+ resampler->pos = (resampler->start << 1) - 1 - resampler->pos;
+ resampler->subpos ^= 65535;
+ /* By rights, time_lost would be updated here. However, there is no
+ * need at this point; it will not be used.
+ *
+ * ((IT_PLAYING *)data)->time_lost += (resampler->src_end - resampler->src_start) << 1;
+ */
+ resampler->dir = 1;
+ } else
+ resampler->dir = 0;
+}
+
+
+
+static void it_playing_update_resamplers(IT_PLAYING *playing)
+{
+ if ((playing->sample->flags & IT_SAMPLE_SUS_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) {
+ playing->resampler.start = playing->sample->sus_loop_start;
+ playing->resampler.end = playing->sample->sus_loop_end;
+ if (playing->resampler.start == playing->resampler.end)
+ playing->resampler.pickup = &it_pickup_stop_at_end;
+ else if (playing->sample->flags & IT_SAMPLE_PINGPONG_SUS_LOOP)
+ playing->resampler.pickup = &it_pickup_pingpong_loop;
+ else
+ playing->resampler.pickup = &it_pickup_loop;
+ } else if (playing->sample->flags & IT_SAMPLE_LOOP) {
+ playing->resampler.start = playing->sample->loop_start;
+ playing->resampler.end = playing->sample->loop_end;
+ if (playing->resampler.start == playing->resampler.end)
+ playing->resampler.pickup = &it_pickup_stop_at_end;
+ else if (playing->sample->flags & IT_SAMPLE_PINGPONG_LOOP)
+ playing->resampler.pickup = &it_pickup_pingpong_loop;
+ else
+ playing->resampler.pickup = &it_pickup_loop;
+ } else {
+ if (playing->sample->flags & IT_SAMPLE_SUS_LOOP)
+ playing->resampler.start = playing->sample->sus_loop_start;
+ else
+ playing->resampler.start = 0;
+ playing->resampler.end = playing->sample->length;
+ playing->resampler.pickup = &it_pickup_stop_at_end;
+ }
+ ASSERT(playing->resampler.pickup_data == playing);
+}
+
+
+
+/* This should be called whenever the sample or sample position changes. */
+static void it_playing_reset_resamplers(IT_PLAYING *playing, long pos)
+{
+ int bits = playing->sample->flags & IT_SAMPLE_16BIT ? 16 : 8;
+ int quality = playing->resampling_quality;
+ int channels = playing->sample->flags & IT_SAMPLE_STEREO ? 2 : 1;
+ if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality)
+ quality = playing->sample->max_resampling_quality;
+ dumb_reset_resampler_n(bits, &playing->resampler, playing->sample->data, channels, pos, 0, 0, quality);
+ playing->resampler.pickup_data = playing;
+ playing->time_lost = 0;
+ playing->flags &= ~IT_PLAYING_DEAD;
+ it_playing_update_resamplers(playing);
+}
+
+static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel);
+
+/* Should we only be retriggering short samples on XM? */
+
+static void update_retrig(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel)
+{
+ if (channel->xm_retrig) {
+ channel->retrig_tick--;
+ if (channel->retrig_tick <= 0) {
+ if (channel->playing) {
+ it_playing_reset_resamplers(channel->playing, 0);
+#ifdef END_RAMPING
+ channel->playing->declick_stage = 0;
+ channel->playing->declick_volume = 1.f / 256.f;
+#endif
+ } else if (sigrenderer->sigdata->flags & IT_WAS_AN_XM) it_retrigger_note(sigrenderer, channel);
+ channel->retrig_tick = channel->xm_retrig;
+ }
+ } else if (channel->retrig & 0x0F) {
+ channel->retrig_tick--;
+ if (channel->retrig_tick <= 0) {
+ if (channel->retrig < 0x10) {
+ } else if (channel->retrig < 0x20) {
+ channel->volume--;
+ if (channel->volume > 64) channel->volume = 0;
+ } else if (channel->retrig < 0x30) {
+ channel->volume -= 2;
+ if (channel->volume > 64) channel->volume = 0;
+ } else if (channel->retrig < 0x40) {
+ channel->volume -= 4;
+ if (channel->volume > 64) channel->volume = 0;
+ } else if (channel->retrig < 0x50) {
+ channel->volume -= 8;
+ if (channel->volume > 64) channel->volume = 0;
+ } else if (channel->retrig < 0x60) {
+ channel->volume -= 16;
+ if (channel->volume > 64) channel->volume = 0;
+ } else if (channel->retrig < 0x70) {
+ channel->volume <<= 1;
+ channel->volume /= 3;
+ } else if (channel->retrig < 0x80) {
+ channel->volume >>= 1;
+ } else if (channel->retrig < 0x90) {
+ } else if (channel->retrig < 0xA0) {
+ channel->volume++;
+ if (channel->volume > 64) channel->volume = 64;
+ } else if (channel->retrig < 0xB0) {
+ channel->volume += 2;
+ if (channel->volume > 64) channel->volume = 64;
+ } else if (channel->retrig < 0xC0) {
+ channel->volume += 4;
+ if (channel->volume > 64) channel->volume = 64;
+ } else if (channel->retrig < 0xD0) {
+ channel->volume += 8;
+ if (channel->volume > 64) channel->volume = 64;
+ } else if (channel->retrig < 0xE0) {
+ channel->volume += 16;
+ if (channel->volume > 64) channel->volume = 64;
+ } else if (channel->retrig < 0xF0) {
+ channel->volume *= 3;
+ channel->volume >>= 1;
+ if (channel->volume > 64) channel->volume = 64;
+ } else {
+ channel->volume <<= 1;
+ if (channel->volume > 64) channel->volume = 64;
+ }
+ if (channel->playing) {
+ it_playing_reset_resamplers(channel->playing, 0);
+#ifdef END_RAMPING
+ channel->playing->declick_stage = 0;
+ channel->playing->declick_volume = 1.f / 256.f;
+#endif
+ } else if (sigrenderer->sigdata->flags & IT_WAS_AN_XM) it_retrigger_note(sigrenderer, channel);
+ channel->retrig_tick = channel->retrig & 0x0F;
+ }
+ }
+}
+
+
+
+static void update_smooth_effects(DUMB_IT_SIGRENDERER *sigrenderer)
+{
+ int i;
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ IT_CHANNEL *channel = &sigrenderer->channel[i];
+ IT_PLAYING *playing = channel->playing;
+
+ if (playing) {
+ playing->vibrato_time += playing->vibrato_n *
+ (playing->vibrato_speed << 2);
+ playing->tremolo_time += playing->tremolo_speed << 2;
+ playing->panbrello_time += playing->panbrello_speed;
+ if (playing->panbrello_waveform == 3)
+ playing->panbrello_random = (rand() % 129) - 64;
+ }
+ }
+}
+
+
+
+static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer)
+{
+ int i;
+
+ if (sigrenderer->globalvolslide) {
+ sigrenderer->globalvolume += sigrenderer->globalvolslide;
+ if (sigrenderer->globalvolume > 128) {
+ if (sigrenderer->globalvolslide >= 0)
+ sigrenderer->globalvolume = 128;
+ else
+ sigrenderer->globalvolume = 0;
+ }
+ }
+
+ if (sigrenderer->temposlide) {
+ sigrenderer->tempo += sigrenderer->temposlide;
+ if (sigrenderer->tempo < 32) {
+ if (sigrenderer->temposlide >= 0)
+ sigrenderer->tempo = 255;
+ else
+ sigrenderer->tempo = 32;
+ }
+ }
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ IT_CHANNEL *channel = &sigrenderer->channel[i];
+ IT_PLAYING *playing = channel->playing;
+
+ if (channel->xm_volslide) {
+ channel->volume += channel->xm_volslide;
+ if (channel->volume > 64) {
+ if (channel->xm_volslide >= 0)
+ channel->volume = 64;
+ else
+ channel->volume = 0;
+ }
+ }
+
+ if (channel->volslide) {
+ channel->volume += channel->volslide;
+ if (channel->volume > 64) {
+ if (channel->volslide >= 0)
+ channel->volume = 64;
+ else
+ channel->volume = 0;
+ }
+ }
+
+ if (channel->panslide) {
+ if (sigrenderer->sigdata->flags & IT_WAS_AN_XM) {
+ if (IT_IS_SURROUND(channel->pan))
+ {
+ channel->pan = 32;
+ channel->truepan = 32 + 128 * 64;
+ }
+ if (channel->panslide == -128)
+ channel->truepan = 32;
+ else
+ channel->truepan = MID(32, channel->truepan + channel->panslide*64, 32+255*64);
+ } else {
+ if (IT_IS_SURROUND(channel->pan))
+ {
+ channel->pan = 32;
+ }
+ channel->pan += channel->panslide;
+ if (channel->pan > 64) {
+ if (channel->panslide >= 0)
+ channel->pan = 64;
+ else
+ channel->pan = 0;
+ }
+ channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
+ }
+ }
+
+ if (channel->channelvolslide) {
+ channel->channelvolume += channel->channelvolslide;
+ if (channel->channelvolume > 64) {
+ if (channel->channelvolslide >= 0)
+ channel->channelvolume = 64;
+ else
+ channel->channelvolume = 0;
+ }
+ if (channel->playing)
+ channel->playing->channel_volume = channel->channelvolume;
+ }
+
+ update_tremor(channel);
+
+ channel->arpeggio = (channel->arpeggio << 4) | (channel->arpeggio >> 8);
+ channel->arpeggio &= 0xFFF;
+
+ update_retrig(sigrenderer, channel);
+
+ if (playing) {
+ playing->slide += channel->portamento;
+
+ if (channel->ptm_toneslide) {
+ if (--channel->toneslide_tick == 0) {
+ channel->toneslide_tick = channel->ptm_toneslide;
+ playing->note += channel->toneslide;
+ if (playing->note >= 120) {
+ if (channel->toneslide < 0) playing->note = 0;
+ else playing->note = 119;
+ }
+ channel->note = channel->truenote = playing->note;
+ if (channel->toneslide_retrig) {
+ it_playing_reset_resamplers(playing, 0);
+#ifdef END_RAMPING
+ playing->declick_stage = 0;
+ playing->declick_volume = 1.f / 256.f;
+#endif
+ }
+ }
+ }
+
+ if (sigrenderer->sigdata->flags & IT_LINEAR_SLIDES) {
+ if (channel->toneporta && channel->destnote < 120) {
+ int currpitch = ((playing->note - 60) << 8) + playing->slide;
+ int destpitch = (channel->destnote - 60) << 8;
+ if (currpitch > destpitch) {
+ currpitch -= channel->toneporta;
+ if (currpitch < destpitch) {
+ currpitch = destpitch;
+ channel->destnote = IT_NOTE_OFF;
+ }
+ } else if (currpitch < destpitch) {
+ currpitch += channel->toneporta;
+ if (currpitch > destpitch) {
+ currpitch = destpitch;
+ channel->destnote = IT_NOTE_OFF;
+ }
+ }
+ playing->slide = currpitch - ((playing->note - 60) << 8);
+ }
+ } else {
+ if (channel->toneporta && channel->destnote < 120) {
+ float amiga_multiplier = playing->sample->C5_speed * (1.0f / AMIGA_DIVISOR);
+
+ float deltanote = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note);
+ /* deltanote is 1.0 for C-5, 0.5 for C-6, etc. */
+
+ float deltaslid = deltanote - playing->slide * amiga_multiplier;
+
+ float destdelta = (float)pow(DUMB_SEMITONE_BASE, 60 - channel->destnote);
+ if (deltaslid < destdelta) {
+ playing->slide -= channel->toneporta;
+ deltaslid = deltanote - playing->slide * amiga_multiplier;
+ if (deltaslid > destdelta) {
+ playing->note = channel->destnote;
+ playing->slide = 0;
+ channel->destnote = IT_NOTE_OFF;
+ }
+ } else {
+ playing->slide += channel->toneporta;
+ deltaslid = deltanote - playing->slide * amiga_multiplier;
+ if (deltaslid < destdelta) {
+ playing->note = channel->destnote;
+ playing->slide = 0;
+ channel->destnote = IT_NOTE_OFF;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ update_smooth_effects(sigrenderer);
+}
+
+
+static void it_note_off(IT_PLAYING *playing);
+
+// This function should be renamed; it doesn't do the 'Update Pattern Variables' operation ittech.txt describes
+/* Returns 1 if a pattern loop is happening. */
+static int update_pattern_variables(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry)
+{
+ IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];
+
+ if (entry->mask & IT_ENTRY_EFFECT) {
+ switch (entry->effect) {
+ case IT_JUMP_TO_ORDER:
+ /* XXX jump and break in same row */
+ if ( ( ( sigrenderer->processrow | 0xC00 ) == 0xFFFE ) &&
+ ! ( sigrenderer->processrow & 0x800 ) ) {
+ sigrenderer->processrow = 0xFFFE & ~0xC00;
+ } else {
+ sigrenderer->breakrow = 0;
+ sigrenderer->processrow = 0xFFFE & ~0x400;
+ }
+ sigrenderer->processorder = entry->effectvalue - 1;
+ break;
+
+ case IT_S:
+ {
+ unsigned char effectvalue = entry->effectvalue;
+ if (effectvalue == 0)
+ effectvalue = channel->lastS;
+ channel->lastS = effectvalue;
+ switch (effectvalue >> 4) {
+ case IT_S_PATTERN_LOOP:
+ {
+ unsigned char v = effectvalue & 15;
+ if (v == 0) {
+#ifdef BIT_ARRAY_BULLSHIT
+ if (!channel->played_patjump)
+ channel->played_patjump = bit_array_create(256);
+ else {
+ //if (channel->played_patjump_order != sigrenderer->order)
+ bit_array_reset(channel->played_patjump);
+ }
+ channel->played_patjump_order = sigrenderer->order;
+#endif
+ channel->pat_loop_row = sigrenderer->processrow;
+ } else {
+ if (channel->pat_loop_count == 0) {
+#ifdef BIT_ARRAY_BULLSHIT
+ /* wft, uninitialized and no start marker yet... */
+ if (channel->played_patjump_order == 0xFFFE) {
+ int n;
+ bit_array_destroy(channel->played_patjump);
+ channel->played_patjump = bit_array_create(256);
+ for (n = 0; n < 256; n++)
+ bit_array_clear(sigrenderer->played, sigrenderer->order * 256 + n);
+ channel->played_patjump_order = sigrenderer->order;
+ } else if (channel->played_patjump_order == sigrenderer->order) {
+ bit_array_set(channel->played_patjump, sigrenderer->row);
+ bit_array_mask(sigrenderer->played, channel->played_patjump, channel->played_patjump_order * 256);
+ bit_array_reset(channel->played_patjump);
+ }
+#endif
+ channel->pat_loop_count = v;
+ sigrenderer->breakrow = channel->pat_loop_row;
+ if ((sigrenderer->sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD)) == IT_WAS_AN_XM) {
+ /* For XM files, if a loop occurs by itself, keep breakrow set for when the pattern ends - fun bug in FT2! */
+ if ((sigrenderer->processrow|0xC00) < 0xFFFE) {
+ /* Infinite pattern loops are possible, so we check whether the pattern loop we're hitting now is earlier than the last one we hit. */
+ if (sigrenderer->processrow < channel->pat_loop_end_row)
+ sigrenderer->processorder = 0xFFFE; /* suspect infinite loop, so trigger loop callback */
+ else
+ sigrenderer->processorder = 0xFFFF; /* don't trigger loop callback */
+ channel->pat_loop_end_row = sigrenderer->processrow;
+ sigrenderer->processrow = 0xFFFF; /* special case: don't reset breakrow or pat_loop_end_row */
+ }
+ } else {
+ /* IT files do this regardless of other flow control effects seen here. */
+ sigrenderer->processorder = 0xFFFF; /* special case: don't trigger loop callback */
+ sigrenderer->processrow = 0xFFFE;
+ }
+ return 1;
+ } else if (--channel->pat_loop_count) {
+#ifdef BIT_ARRAY_BULLSHIT
+ if (channel->played_patjump_order == sigrenderer->order) {
+ bit_array_set(channel->played_patjump, sigrenderer->row);
+ bit_array_mask(sigrenderer->played, channel->played_patjump, channel->played_patjump_order * 256);
+ bit_array_reset(channel->played_patjump);
+ }
+#endif
+ sigrenderer->breakrow = channel->pat_loop_row;
+ if ((sigrenderer->sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD)) == IT_WAS_AN_XM) {
+ /* For XM files, if a loop occurs by itself, keep breakrow set for when the pattern ends - fun bug in FT2! */
+ if ((sigrenderer->processrow|0xC00) < 0xFFFE) {
+ /* Infinite pattern loops are possible, so we check whether the pattern loop we're hitting now is earlier than the last one we hit. */
+ if (sigrenderer->processrow < channel->pat_loop_end_row)
+ sigrenderer->processorder = 0xFFFE; /* suspect infinite loop, so trigger loop callback */
+ else
+ sigrenderer->processorder = 0xFFFF; /* don't trigger loop callback */
+ channel->pat_loop_end_row = sigrenderer->processrow;
+ sigrenderer->processrow = 0xFFFF; /* special case: don't reset breakrow or pat_loop_end_row */
+ }
+ } else {
+ /* IT files do this regardless of other flow control effects seen here. */
+ sigrenderer->processorder = 0xFFFF; /* special case: don't trigger loop callback */
+ sigrenderer->processrow = 0xFFFE;
+ }
+ return 1;
+ } else if ((sigrenderer->sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD)) == IT_WAS_AN_XM) {
+ channel->pat_loop_end_row = 0;
+ // TODO
+ /* Findings:
+ - If a pattern loop completes successfully, and then the pattern terminates, then the next pattern will start on the row corresponding to the E60.
+ - If a pattern loop doesn't do any loops, and then the pattern terminates, then the next pattern will start on the first row.
+ - If a break appears to the left of the pattern loop, it jumps into the relevant position in the next pattern, and that's it.
+ - If a break appears to the right of the pattern loop, it jumps to the start of the next pattern, and that's it.
+ - If we jump, then effect a loop using an old E60, and then the pattern ends, the next pattern starts on the row corresponding to the E60.
+ - Theory: breakrow is not cleared when it's a pattern loop effect!
+ */
+ //if (sigrenderer->processrow < 0xFFFE) // I have no idea if this is correct or not - FT2 is so weird :(
+ // sigrenderer->breakrow = channel->pat_loop_row; /* emulate bug in FT2 */
+ } else
+ channel->pat_loop_row = sigrenderer->processrow + 1;
+#ifdef BIT_ARRAY_BULLSHIT
+ /*channel->played_patjump_order |= 0x8000;*/
+ if (channel->played_patjump_order == sigrenderer->order) {
+ bit_array_destroy(channel->played_patjump);
+ channel->played_patjump = 0;
+ channel->played_patjump_order = 0xFFFE;
+ }
+ bit_array_clear(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row);
+#endif
+ }
+ }
+ break;
+ case IT_S_PATTERN_DELAY:
+ sigrenderer->rowcount = 1 + (effectvalue & 15);
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+/* This function guarantees that channel->sample will always be valid if it
+ * is nonzero. In other words, to check if it is valid, simply check if it is
+ * nonzero.
+ */
+static void instrument_to_sample(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel)
+{
+ if (sigdata->flags & IT_USE_INSTRUMENTS) {
+ if (channel->instrument >= 1 && channel->instrument <= sigdata->n_instruments) {
+ if (channel->note < 120) {
+ channel->sample = sigdata->instrument[channel->instrument-1].map_sample[channel->note];
+ channel->truenote = sigdata->instrument[channel->instrument-1].map_note[channel->note];
+ } else
+ channel->sample = 0;
+ } else
+ channel->sample = 0;
+ } else {
+ channel->sample = channel->instrument;
+ channel->truenote = channel->note;
+ }
+ if (!(channel->sample >= 1 && channel->sample <= sigdata->n_samples && (sigdata->sample[channel->sample-1].flags & IT_SAMPLE_EXISTS) && sigdata->sample[channel->sample-1].C5_speed))
+ channel->sample = 0;
+}
+
+
+
+static void fix_sample_looping(IT_PLAYING *playing)
+{
+ if ((playing->sample->flags & (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP)) ==
+ (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP)) {
+ if (playing->resampler.dir < 0) {
+ playing->resampler.pos = (playing->sample->sus_loop_end << 1) - 1 - playing->resampler.pos;
+ playing->resampler.subpos ^= 65535;
+ playing->resampler.dir = 1;
+ }
+
+ playing->resampler.pos += playing->time_lost;
+ // XXX what
+ playing->time_lost = 0;
+ }
+}
+
+
+
+static void it_compatible_gxx_retrigger(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel)
+{
+ int flags = 0;
+ if (channel->sample) {
+ if (sigdata->flags & IT_USE_INSTRUMENTS) {
+ if (channel->playing->env_instrument == &sigdata->instrument[channel->instrument-1]) {
+ if (channel->playing->env_instrument->volume_envelope.flags & IT_ENVELOPE_CARRY)
+ flags |= 1;
+ if (channel->playing->env_instrument->pan_envelope.flags & IT_ENVELOPE_CARRY)
+ flags |= 2;
+ if (channel->playing->env_instrument->pitch_envelope.flags & IT_ENVELOPE_CARRY)
+ flags |= 4;
+ }
+ }
+ }
+ if (!(flags & 1)) {
+ channel->playing->volume_envelope.next_node = 0;
+ channel->playing->volume_envelope.tick = 0;
+ }
+ if (!(flags & 2)) {
+ channel->playing->pan_envelope.next_node = 0;
+ channel->playing->pan_envelope.tick = 0;
+ }
+ if (!(flags & 4)) {
+ channel->playing->pitch_envelope.next_node = 0;
+ channel->playing->pitch_envelope.tick = 0;
+ }
+ channel->playing->fadeoutcount = 1024;
+ // Should we remove IT_PLAYING_BACKGROUND? Test with sample with sustain loop...
+ channel->playing->flags &= ~(IT_PLAYING_BACKGROUND | IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING | IT_PLAYING_DEAD);
+ it_playing_update_resamplers(channel->playing);
+
+ if (!flags && channel->sample)
+ if (sigdata->flags & IT_USE_INSTRUMENTS)
+ channel->playing->env_instrument = &sigdata->instrument[channel->instrument-1];
+}
+
+
+
+static void it_note_off(IT_PLAYING *playing)
+{
+ if (playing) {
+ playing->enabled_envelopes |= IT_ENV_VOLUME;
+ playing->flags |= IT_PLAYING_BACKGROUND | IT_PLAYING_SUSTAINOFF;
+ fix_sample_looping(playing);
+ it_playing_update_resamplers(playing);
+ if (playing->instrument)
+ if ((playing->instrument->volume_envelope.flags & (IT_ENVELOPE_ON | IT_ENVELOPE_LOOP_ON)) != IT_ENVELOPE_ON)
+ playing->flags |= IT_PLAYING_FADING;
+ }
+}
+
+
+
+static void xm_note_off(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel)
+{
+ if (channel->playing) {
+ if (channel->instrument > sigdata->n_instruments ||
+ !(sigdata->instrument[channel->instrument-1].volume_envelope.flags & IT_ENVELOPE_ON))
+ //if (!(entry->mask & IT_ENTRY_INSTRUMENT))
+ // dunno what that was there for ...
+ channel->volume = 0;
+ channel->playing->flags |= IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING;
+ it_playing_update_resamplers(channel->playing);
+ }
+}
+
+
+
+static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel)
+{
+ IT_PLAYING_ENVELOPE volume_envelope;
+ IT_PLAYING_ENVELOPE pan_envelope;
+ IT_PLAYING_ENVELOPE pitch_envelope;
+
+ DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
+ unsigned char nna;
+ int i, flags = 0;
+
+ if (channel->playing) {
+#ifdef INVALID_NOTES_CAUSE_NOTE_CUT
+ if (channel->note == IT_NOTE_OFF)
+ nna = NNA_NOTE_OFF;
+ else if (channel->note >= 120 || !channel->playing->instrument || (channel->playing->flags & IT_PLAYING_DEAD))
+ nna = NNA_NOTE_CUT;
+ else if (channel->new_note_action != 0xFF)
+ {
+ nna = channel->new_note_action;
+ }
+ else
+ nna = channel->playing->instrument->new_note_action;
+#else
+ if (channel->note == IT_NOTE_CUT)
+ nna = NNA_NOTE_CUT;
+ if (channel->note >= 120)
+ nna = NNA_NOTE_OFF;
+ else if (!channel->playing->instrument || (channel->playing->flags & IT_PLAYING_DEAD))
+ nna = NNA_NOTE_CUT;
+ else if (channel->new_note_action != 0xFF)
+ {
+ nna = channel->new_note_action;
+ }
+ else
+ nna = channel->playing->instrument->new_note_action;
+#endif
+
+ if ((sigdata->flags & IT_USE_INSTRUMENTS) && (channel->playing->enabled_envelopes) && channel->playing->instnum == channel->instrument) {
+ IT_PLAYING * playing = channel->playing;
+ IT_INSTRUMENT * inst = &sigdata->instrument[channel->instrument-1];
+ if ((playing->enabled_envelopes & IT_ENV_VOLUME) && (inst->volume_envelope.flags & IT_ENVELOPE_CARRY)) {
+ flags |= 1;
+ volume_envelope = playing->volume_envelope;
+ }
+ if ((playing->enabled_envelopes & IT_ENV_PANNING) && (inst->pan_envelope.flags & IT_ENVELOPE_CARRY)) {
+ flags |= 2;
+ pan_envelope = playing->pan_envelope;
+ }
+ if ((playing->enabled_envelopes & IT_ENV_PITCH) && (inst->pitch_envelope.flags & IT_ENVELOPE_CARRY)) {
+ flags |= 4;
+ pitch_envelope = playing->pitch_envelope;
+ }
+ }
+
+ switch (nna) {
+ case NNA_NOTE_CUT:
+#ifdef RAMP_DOWN
+ channel->playing->declick_stage = 2;
+#else
+ free(channel->playing);
+ channel->playing = NULL;
+#endif
+ break;
+ case NNA_NOTE_OFF:
+ it_note_off(channel->playing);
+ break;
+ case NNA_NOTE_FADE:
+ channel->playing->flags |= IT_PLAYING_BACKGROUND | IT_PLAYING_FADING;
+ break;
+ }
+ }
+
+ channel->new_note_action = 0xFF;
+
+ if (channel->sample == 0 || channel->note >= 120)
+ return;
+
+ channel->destnote = IT_NOTE_OFF;
+
+ if (channel->playing) {
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
+ if (!sigrenderer->playing[i]) {
+ sigrenderer->playing[i] = channel->playing;
+ channel->playing = NULL;
+ break;
+ }
+ }
+
+ if (sigrenderer->sigdata->flags & IT_USE_INSTRUMENTS)
+ {
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
+ IT_PLAYING * playing = sigrenderer->playing[i];
+ if (playing && playing->channel == channel && playing->instrument->dup_check_type) {
+ int match = 0;
+ switch (playing->instrument->dup_check_type)
+ {
+ case DCT_NOTE:
+ match = (channel->truenote == playing->note);
+ case DCT_SAMPLE:
+ match = match && (channel->sample == playing->sampnum);
+ case DCT_INSTRUMENT:
+ match = match && (channel->instrument == playing->instnum);
+ break;
+ }
+
+ if (match)
+ {
+ switch (playing->instrument->dup_check_action)
+ {
+ case DCA_NOTE_CUT:
+#ifdef RAMP_DOWN
+ playing->declick_stage = 2;
+#else
+ free(playing);
+ sigrenderer->playing[i] = NULL;
+#endif
+ if (channel->playing == playing) channel->playing = NULL;
+ break;
+ case DCA_NOTE_OFF:
+ if (!(playing->flags & IT_PLAYING_SUSTAINOFF))
+ it_note_off(playing);
+ break;
+ case DCA_NOTE_FADE:
+ playing->flags |= IT_PLAYING_BACKGROUND | IT_PLAYING_FADING;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+/** WARNING - come up with some more heuristics for replacing old notes */
+#if 0
+ if (channel->playing) {
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
+ if (sigrenderer->playing[i]->flags & IT_PLAYING_BACKGROUND) {
+ write_seqtime();
+ sequence_c(SEQUENCE_STOP_SIGNAL);
+ sequence_c(i);
+ channel->VChannel = &module->VChannel[i];
+ break;
+ }
+ }
+ }
+#endif
+ }
+
+ if (channel->playing)
+ free(channel->playing);
+
+ channel->playing = malloc(sizeof(*channel->playing));
+
+ if (!channel->playing)
+ return;
+
+ if (!flags && sigdata->flags & IT_USE_INSTRUMENTS) {
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
+ IT_PLAYING * playing = sigrenderer->playing[i];
+ if (playing && (playing->enabled_envelopes) && playing->instnum == channel->instrument) {
+ IT_INSTRUMENT * inst = &sigdata->instrument[channel->instrument-1];
+ if ((playing->enabled_envelopes & IT_ENV_VOLUME) && (inst->volume_envelope.flags & IT_ENVELOPE_CARRY)) {
+ flags |= 1;
+ volume_envelope = playing->volume_envelope;
+ }
+ if ((playing->enabled_envelopes & IT_ENV_PANNING) && (inst->pan_envelope.flags & IT_ENVELOPE_CARRY)) {
+ flags |= 2;
+ pan_envelope = playing->pan_envelope;
+ }
+ if ((playing->enabled_envelopes & IT_ENV_PITCH) && (inst->pitch_envelope.flags & IT_ENVELOPE_CARRY)) {
+ flags |= 4;
+ pitch_envelope = playing->pitch_envelope;
+ }
+ break;
+ }
+ }
+ }
+
+ 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;
+#ifdef END_RAMPING
+ channel->playing->declick_stage = 0;
+ channel->playing->declick_volume = 1.f / 256.f;
+#endif
+ channel->playing->channel_volume = channel->channelvolume;
+ channel->playing->ramp_volume[0] = 31337.0; /* special */
+ 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->pitch_envelope.flags & IT_ENVELOPE_ON) playing->enabled_envelopes |= IT_ENV_PITCH;
+ if (instrument->random_volume) playing->volume_offset = (rand() % (instrument->random_volume * 2 + 1)) - instrument->random_volume;
+ if (instrument->random_pan) playing->panning_offset = (rand() % (instrument->random_pan * 2 + 1)) - instrument->random_pan;
+ //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 = channel->vibrato_waveform;
+ channel->playing->tremolo_speed = 0;
+ channel->playing->tremolo_depth = 0;
+ channel->playing->tremolo_time = 0;
+ channel->playing->tremolo_waveform = channel->tremolo_waveform;
+ channel->playing->panbrello_speed = 0;
+ channel->playing->panbrello_depth = 0;
+ channel->playing->panbrello_time = 0;
+ channel->playing->panbrello_waveform = channel->panbrello_waveform;
+ 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;
+
+ if (flags & 1) {
+ channel->playing->volume_envelope = volume_envelope;
+ } else {
+ channel->playing->volume_envelope.next_node = 0;
+ channel->playing->volume_envelope.tick = 0;
+ }
+ if (flags & 2) {
+ channel->playing->pan_envelope = pan_envelope;
+ } else {
+ channel->playing->pan_envelope.next_node = 0;
+ channel->playing->pan_envelope.tick = 0;
+ }
+ if (flags & 4) {
+ channel->playing->pitch_envelope = pitch_envelope;
+ } else {
+ channel->playing->pitch_envelope.next_node = 0;
+ channel->playing->pitch_envelope.tick = 0;
+ }
+ channel->playing->fadeoutcount = 1024;
+ it_reset_filter_state(&channel->playing->filter_state[0]);
+ it_reset_filter_state(&channel->playing->filter_state[1]);
+ it_playing_reset_resamplers(channel->playing, 0);
+
+ /** WARNING - is everything initialised? */
+}
+
+
+
+static void get_default_volpan(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel)
+{
+ if (channel->sample == 0)
+ return;
+
+ channel->volume = sigdata->sample[channel->sample-1].default_volume;
+
+ if (sigdata->flags & IT_WAS_AN_XM) {
+ if (!(sigdata->flags & IT_WAS_A_MOD))
+ channel->truepan = 32 + sigdata->sample[channel->sample-1].default_pan*64;
+ return;
+ }
+
+ {
+ int pan = sigdata->sample[channel->sample-1].default_pan;
+ if (pan >= 128 && pan <= 192) {
+ channel->pan = pan - 128;
+ return;
+ }
+ }
+
+ if (sigdata->flags & IT_USE_INSTRUMENTS) {
+ IT_INSTRUMENT *instrument = &sigdata->instrument[channel->instrument-1];
+ if (instrument->default_pan <= 64)
+ channel->pan = instrument->default_pan;
+ if (instrument->filter_cutoff >= 128)
+ channel->filter_cutoff = instrument->filter_cutoff - 128;
+ if (instrument->filter_resonance >= 128)
+ channel->filter_resonance = instrument->filter_resonance - 128;
+ }
+}
+
+
+
+static void get_true_pan(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel)
+{
+ channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
+
+ if (channel->sample && !IT_IS_SURROUND_SHIFTED(channel->truepan) && (sigdata->flags & IT_USE_INSTRUMENTS)) {
+ IT_INSTRUMENT *instrument = &sigdata->instrument[channel->instrument-1];
+ int truepan = channel->truepan;
+ truepan += (channel->note - instrument->pp_centre) * instrument->pp_separation << (IT_ENVELOPE_SHIFT - 3);
+ channel->truepan = (unsigned short)MID(0, truepan, 64 << IT_ENVELOPE_SHIFT);
+ }
+}
+
+
+
+static void post_process_it_volpan(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry)
+{
+ IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];
+
+ if (entry->mask & IT_ENTRY_VOLPAN) {
+ if (entry->volpan <= 84) {
+ /* Volume */
+ /* Fine volume slide up */
+ /* Fine volume slide down */
+ } else if (entry->volpan <= 94) {
+ /* Volume slide up */
+ unsigned char v = entry->volpan - 85;
+ if (v == 0)
+ v = channel->lastvolslide;
+ channel->lastvolslide = v;
+ /* = effect Dx0 where x == entry->volpan - 85 */
+ channel->volslide = v;
+ } else if (entry->volpan <= 104) {
+ /* Volume slide down */
+ unsigned char v = entry->volpan - 95;
+ if (v == 0)
+ v = channel->lastvolslide;
+ channel->lastvolslide = v;
+ /* = effect D0x where x == entry->volpan - 95 */
+ channel->volslide = -v;
+ } else if (entry->volpan <= 114) {
+ /* Portamento down */
+ unsigned char v = (entry->volpan - 105) << 2;
+ if (v == 0)
+ v = channel->lastEF;
+ channel->lastEF = v;
+ channel->portamento -= v << 4;
+ } else if (entry->volpan <= 124) {
+ /* Portamento up */
+ unsigned char v = (entry->volpan - 115) << 2;
+ if (v == 0)
+ v = channel->lastEF;
+ channel->lastEF = v;
+ channel->portamento += v << 4;
+ } else if (entry->volpan <= 202) {
+ /* Pan */
+ /* Tone Portamento */
+ } else if (entry->volpan <= 212) {
+ /* Vibrato */
+ /* This is unaffected by IT_OLD_EFFECTS. However, if v == 0, then any doubling of depth that happened before (with Hxy in the effect column) will be preserved. */
+ unsigned char v = entry->volpan - 203;
+ if (v == 0)
+ v = channel->lastHdepth;
+ else {
+ v <<= 2;
+ channel->lastHdepth = v;
+ }
+ if (channel->playing) {
+ channel->playing->vibrato_speed = channel->lastHspeed;
+ channel->playing->vibrato_depth = v;
+ channel->playing->vibrato_n++;
+ }
+ }
+ }
+}
+
+
+
+static void it_send_midi(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel, unsigned char midi_byte)
+{
+ if (sigrenderer->callbacks->midi)
+ if ((*sigrenderer->callbacks->midi)(sigrenderer->callbacks->midi_data, channel - sigrenderer->channel, midi_byte))
+ return;
+
+ switch (channel->midi_state) {
+ case 4: /* Ready to receive resonance parameter */
+ if (midi_byte < 0x80) channel->filter_resonance = midi_byte;
+ channel->midi_state = 0;
+ break;
+ case 3: /* Ready to receive cutoff parameter */
+ if (midi_byte < 0x80) channel->filter_cutoff = midi_byte;
+ channel->midi_state = 0;
+ break;
+ case 2: /* Ready for byte specifying which parameter will follow */
+ if (midi_byte == 0) /* Cutoff */
+ channel->midi_state = 3;
+ else if (midi_byte == 1) /* Resonance */
+ channel->midi_state = 4;
+ else
+ channel->midi_state = 0;
+ break;
+ default: /* Counting initial F0 bytes */
+ switch (midi_byte) {
+ case 0xF0:
+ channel->midi_state++;
+ break;
+ case 0xFA:
+ case 0xFC:
+ case 0xFF:
+ /* Reset filter parameters for all channels */
+ {
+ int i;
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ sigrenderer->channel[i].filter_cutoff = 127;
+ sigrenderer->channel[i].filter_resonance = 0;
+ //// should we be resetting channel[i].playing->filter_* here?
+ }
+ }
+ /* Fall through */
+ default:
+ channel->midi_state = 0;
+ break;
+ }
+ }
+}
+
+
+
+static void xm_envelope_calculate_value(IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe)
+{
+ if (pe->next_node <= 0)
+ pe->value = envelope->node_y[0] << IT_ENVELOPE_SHIFT;
+ else if (pe->next_node >= envelope->n_nodes)
+ pe->value = envelope->node_y[envelope->n_nodes-1] << IT_ENVELOPE_SHIFT;
+ else {
+ int ys = envelope->node_y[pe->next_node-1] << IT_ENVELOPE_SHIFT;
+ int ts = envelope->node_t[pe->next_node-1];
+ int te = envelope->node_t[pe->next_node];
+
+ if (ts == te)
+ pe->value = ys;
+ else {
+ int ye = envelope->node_y[pe->next_node] << IT_ENVELOPE_SHIFT;
+ int t = pe->tick;
+
+ pe->value = ys + (ye - ys) * (t - ts) / (te - ts);
+ }
+ }
+}
+
+
+
+extern const char xm_convert_vibrato[];
+
+/* Returns 1 if a callback caused termination of playback. */
+static int process_effects(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry, int ignore_cxx)
+{
+ DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
+
+ 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;*/
+ 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:
+ if (channel->playing) {
+ channel->playing->vibrato_speed = channel->lastHspeed;
+ channel->playing->vibrato_depth = channel->lastHdepth;
+ channel->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 ((v & 0x0F) == 0) { /* Dx0 */
+ channel->volslide = v >> 4;
+ if (channel->volslide == 15 && !(sigdata->flags & IT_WAS_AN_XM)) {
+ channel->volume += 15;
+ if (channel->volume > 64) channel->volume = 64;
+ }
+ } else if ((v & 0xF0) == 0) { /* D0x */
+ channel->volslide = -v;
+ if (channel->volslide == -15 && !(sigdata->flags & IT_WAS_AN_XM)) {
+ channel->volume -= 15;
+ if (channel->volume > 64) channel->volume = 0;
+ }
+ } 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 (v == 0)
+ v = channel->lastEF;
+ channel->lastEF = v;
+ }
+ if (channel->playing) {
+ if ((v & 0xF0) == 0xF0)
+ channel->playing->slide -= (v & 15) << 4;
+ else if ((v & 0xF0) == 0xE0)
+ channel->playing->slide -= (v & 15) << 2;
+ else if (sigdata->flags & IT_WAS_A_669)
+ channel->portamento -= v << 3;
+ else
+ 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 (v == 0)
+ v = channel->lastEF;
+ channel->lastEF = v;
+ }
+ if (channel->playing) {
+ if ((v & 0xF0) == 0xF0)
+ channel->playing->slide += (v & 15) << 4;
+ else if ((v & 0xF0) == 0xE0)
+ channel->playing->slide += (v & 15) << 2;
+ else if (sigdata->flags & IT_WAS_A_669)
+ channel->portamento += v << 3;
+ else
+ 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)
+ depth <<= 3;
+ else
+ depth <<= 2;
+ channel->lastHdepth = depth;
+ }
+ if (channel->playing) {
+ channel->playing->vibrato_speed = speed;
+ channel->playing->vibrato_depth = depth;
+ channel->playing->vibrato_n++;
+ }
+ }
+ }
+ break;
+ case IT_TREMOR:
+ {
+ unsigned char v = entry->effectvalue;
+ if (v == 0)
+ v = channel->lastI;
+ else if (!(sigdata->flags & IT_OLD_EFFECTS)) {
+ if (v & 0xF0) v -= 0x10;
+ if (v & 0x0F) v -= 0x01;
+ }
+ 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 (v == 0)
+ v = channel->lastJ;
+ channel->lastJ = v;
+ }
+ channel->arpeggio = v;
+ }
+ 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_A_PTM) && (sample->flags & IT_SAMPLE_16BIT))
+ offset >>= 1;
+ if (offset < end) {
+ it_playing_reset_resamplers(playing, offset);
+#ifdef END_RAMPING
+ playing->declick_stage = 0;
+ playing->declick_volume = 1.f / 256.f;
+#endif
+ } else if (sigdata->flags & IT_OLD_EFFECTS) {
+ it_playing_reset_resamplers(playing, end);
+#ifdef END_RAMPING
+ playing->declick_stage = 0;
+ playing->declick_volume = 1.f / 256.f;
+#endif
+ }
+ }
+ }
+ }
+ 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;
+ } 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);
+#ifdef END_RAMPING
+ channel->playing->declick_stage = 0;
+ channel->playing->declick_volume = 1.f / 256.f;
+#endif
+ }
+ break;
+ case IT_TREMOLO:
+ {
+ unsigned char speed = entry->effectvalue >> 4;
+ unsigned char depth = entry->effectvalue & 15;
+ if (speed == 0)
+ speed = channel->lastRspeed;
+ channel->lastRspeed = speed;
+ if (depth == 0)
+ depth = channel->lastRdepth;
+ channel->lastRdepth = depth;
+ if (channel->playing) {
+ channel->playing->tremolo_speed = speed;
+ channel->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_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_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)
+ {
+#ifdef RAMP_DOWN
+ playing->declick_stage = 2;
+#else
+ free(playing);
+ sigrenderer->playing[i] = NULL;
+#endif
+ 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) == 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:
+ 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;
+ }
+ if (channel->playing) {
+ channel->playing->vibrato_speed = speed;
+ channel->playing->vibrato_depth = depth;
+ channel->playing->vibrato_n++;
+ }
+ }
+ break;
+ case IT_SET_GLOBAL_VOLUME:
+ 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) {
+ if (sigdata->flags & IT_WAS_A_MOD)
+ channel->truepan = entry->effectvalue*128;
+ else
+ 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);
+#ifdef END_RAMPING
+ channel->playing->declick_stage = 0;
+ channel->playing->declick_volume = 1.f / 256.f;
+#endif
+ }
+ }
+ }
+
+ 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);
+#ifdef END_RAMPING
+ channel->playing->declick_stage = 0;
+ channel->playing->declick_volume = 1.f / 256.f;
+#endif
+ }
+ }
+ }
+
+ channel->ptm_last_toneslide = 0;
+
+ channel->toneslide = -(entry->effectvalue & 15);
+ channel->ptm_toneslide = (entry->effectvalue & 0xF0) >> 4;
+ channel->toneslide_tick += channel->ptm_toneslide;
+ }
+ break;
+ }
+ }
+
+ if (!(sigdata->flags & IT_WAS_AN_XM))
+ post_process_it_volpan(sigrenderer, entry);
+
+ return 0;
+}
+
+
+
+static int process_it_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry)
+{
+ DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
+ IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];
+
+ // When tone portamento and instrument are specified:
+ // If Gxx is off:
+ // - same sample, do nothing but portamento
+ // - diff sample, retrigger all but keep current note+slide + do porta
+ // - if instrument is invalid, nothing; if sample is invalid, cut
+ // If Gxx is on:
+ // - same sample or new sample invalid, retrigger envelopes and initialise note value for portamento to 'seek' to
+ // - diff sample/inst, start using new envelopes
+ // When tone portamento is specified alone, sample won't change.
+ // TODO: consider what happens with instrument alone after all this...
+
+ if (entry->mask & (IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT)) {
+ if (entry->mask & IT_ENTRY_INSTRUMENT)
+ channel->instrument = entry->instrument;
+ instrument_to_sample(sigdata, channel);
+ if (channel->note < 120) {
+ if ((sigdata->flags & IT_USE_INSTRUMENTS) && channel->sample == 0)
+ it_retrigger_note(sigrenderer, channel); /* Stop the note */ /*return 1;*/
+ if (entry->mask & IT_ENTRY_INSTRUMENT)
+ get_default_volpan(sigdata, channel);
+ } else
+ it_retrigger_note(sigrenderer, channel); /* Stop the note */
+ }
+
+ /** WARNING: This is not ideal, since channel->playing might not get allocated owing to lack of memory... */
+ if (((entry->mask & IT_ENTRY_VOLPAN) && entry->volpan >= 193 && entry->volpan <= 202) ||
+ ((entry->mask & IT_ENTRY_EFFECT) && (entry->effect == IT_TONE_PORTAMENTO || entry->effect == IT_VOLSLIDE_TONEPORTA)))
+ {
+ if (channel->playing && (entry->mask & IT_ENTRY_INSTRUMENT)) {
+ if (sigdata->flags & IT_COMPATIBLE_GXX)
+ it_compatible_gxx_retrigger(sigdata, channel);
+ else if ((!(sigdata->flags & IT_USE_INSTRUMENTS) ||
+ (channel->instrument >= 1 && channel->instrument <= sigdata->n_instruments)) &&
+ channel->sample != channel->playing->sampnum)
+ {
+ unsigned char note = channel->playing->note;
+ int slide = channel->playing->slide;
+ it_retrigger_note(sigrenderer, channel);
+ if (channel->playing) {
+ channel->playing->note = note;
+ channel->playing->slide = slide;
+ // Should we be preserving sample_vibrato_time? depth?
+ }
+ }
+ }
+
+ if ((entry->mask & IT_ENTRY_VOLPAN) && entry->volpan >= 193 && entry->volpan <= 202) {
+ /* Tone Portamento in the volume column */
+ static const unsigned char slidetable[] = {0, 1, 4, 8, 16, 32, 64, 96, 128, 255};
+ unsigned char v = slidetable[entry->volpan - 193];
+ if (sigdata->flags & IT_COMPATIBLE_GXX) {
+ if (v == 0)
+ v = channel->lastG;
+ channel->lastG = v;
+ } else {
+ if (v == 0)
+ v = channel->lastEF;
+ channel->lastEF = v;
+ }
+ if ((entry->mask & IT_ENTRY_NOTE) || ((sigdata->flags & IT_COMPATIBLE_GXX) && (entry->mask & IT_ENTRY_INSTRUMENT))) {
+ if (channel->note < 120) {
+ if (channel->sample)
+ channel->destnote = channel->truenote;
+ else
+ channel->destnote = channel->note;
+ }
+ }
+ channel->toneporta = v << 4;
+ } else {
+ /* Tone Portamento in the effect column */
+ unsigned char v;
+ if (entry->effect == IT_TONE_PORTAMENTO)
+ v = entry->effectvalue;
+ else
+ v = 0;
+ if (sigdata->flags & IT_COMPATIBLE_GXX) {
+ if (v == 0)
+ v = channel->lastG;
+ channel->lastG = v;
+ } else {
+ if (v == 0 && !(sigdata->flags & IT_WAS_A_669))
+ v = channel->lastEF;
+ channel->lastEF = v;
+ }
+ if ((entry->mask & IT_ENTRY_NOTE) || ((sigdata->flags & IT_COMPATIBLE_GXX) && (entry->mask & IT_ENTRY_INSTRUMENT))) {
+ if (channel->note < 120) {
+ if (channel->sample)
+ channel->destnote = channel->truenote;
+ else
+ channel->destnote = channel->note;
+ }
+ }
+ channel->toneporta = v << 4;
+ }
+ if (channel->playing) goto skip_start_note;
+ }
+
+ if ((entry->mask & IT_ENTRY_NOTE) ||
+ ((entry->mask & IT_ENTRY_INSTRUMENT) && (!channel->playing || entry->instrument != channel->playing->instnum)))
+ {
+ if (channel->note < 120) {
+ get_true_pan(sigdata, channel);
+ if ((entry->mask & IT_ENTRY_NOTE) || !(sigdata->flags & (IT_WAS_AN_S3M|IT_WAS_A_PTM)))
+ it_retrigger_note(sigrenderer, channel);
+ }
+ }
+
+ skip_start_note:
+
+ if (entry->mask & IT_ENTRY_VOLPAN) {
+ if (entry->volpan <= 64) {
+ /* Volume */
+ channel->volume = entry->volpan;
+ } else if (entry->volpan <= 74) {
+ /* Fine volume slide up */
+ unsigned char v = entry->volpan - 65;
+ if (v == 0)
+ v = channel->lastvolslide;
+ channel->lastvolslide = v;
+ /* = effect DxF where x == entry->volpan - 65 */
+ channel->volume += v;
+ if (channel->volume > 64) channel->volume = 64;
+ } else if (entry->volpan <= 84) {
+ /* Fine volume slide down */
+ unsigned char v = entry->volpan - 75;
+ if (v == 0)
+ v = channel->lastvolslide;
+ channel->lastvolslide = v;
+ /* = effect DFx where x == entry->volpan - 75 */
+ channel->volume -= v;
+ if (channel->volume > 64) channel->volume = 0;
+ } else if (entry->volpan < 128) {
+ /* Volume slide up */
+ /* Volume slide down */
+ /* Portamento down */
+ /* Portamento up */
+ } else if (entry->volpan <= 192) {
+ /* Pan */
+ channel->pan = entry->volpan - 128;
+ channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
+ }
+ /* else */
+ /* Tone Portamento */
+ /* Vibrato */
+ }
+ return 0;
+}
+
+
+
+static void retrigger_xm_envelopes(IT_PLAYING *playing)
+{
+ playing->volume_envelope.next_node = 0;
+ playing->volume_envelope.tick = -1;
+ playing->pan_envelope.next_node = 0;
+ playing->pan_envelope.tick = -1;
+ playing->fadeoutcount = 1024;
+}
+
+
+
+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;
+
+ playing.sample = 0;
+
+ if (entry->mask & IT_ENTRY_INSTRUMENT) {
+ int oldsample = channel->sample;
+ int oldvolume = channel->volume;
+ 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 = *channel->playing;
+ 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) {
+#ifdef RAMP_DOWN
+ int i;
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
+ if (!sigrenderer->playing[i]) {
+ channel->playing->declick_stage = 2;
+ sigrenderer->playing[i] = channel->playing;
+ channel->playing = NULL;
+ break;
+ }
+ }
+
+ if (!channel->sample) {
+ if (channel->playing)
+ {
+ free(channel->playing);
+ channel->playing = NULL;
+ }
+ } else {
+ if (!channel->playing) {
+ channel->playing = malloc(sizeof(*channel->playing));
+ if (!channel->playing) return;
+ }
+ *channel->playing = playing;
+ playing.sample = (IT_SAMPLE *)-1;
+ channel->playing->declick_stage = 0;
+ channel->playing->declick_volume = 1.f / 256.f;
+#else
+ if (!channel->sample) {
+ free(channel->playing);
+ channel->playing = NULL;
+ } else {
+#endif
+ 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);
+ }
+#ifdef END_RAMPING
+ if (channel->volume && !oldvolume) {
+ channel->playing->declick_stage = 0;
+ channel->playing->declick_volume = 1.f / 256.f;
+ }
+#endif
+ }
+ }
+
+ 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) {
+#ifdef RAMP_DOWN
+ int i;
+ if (playing.sample) *channel->playing = playing;
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
+ if (!sigrenderer->playing[i]) {
+ channel->playing->declick_stage = 2;
+ sigrenderer->playing[i] = channel->playing;
+ channel->playing = NULL;
+ break;
+ }
+ }
+ if (channel->playing) {
+ free(channel->playing);
+ channel->playing = NULL;
+ }
+#else
+ free(channel->playing);
+ channel->playing = NULL;
+#endif
+ }
+ 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 = malloc(sizeof(*channel->playing));
+ if (!channel->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);
+ }
+#ifdef RAMP_DOWN
+ else if (playing.sample != (IT_SAMPLE *)-1) {
+ /* volume rampy stuff! move note to NNA */
+ int i;
+ IT_PLAYING * ptemp = malloc(sizeof(*channel->playing));
+ if (!ptemp) return;
+ if (playing.sample) *ptemp = playing;
+ else *ptemp = *channel->playing;
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
+ if (!sigrenderer->playing[i]) {
+ ptemp->declick_stage = 2;
+ ptemp->flags |= IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING;
+ sigrenderer->playing[i] = ptemp;
+ ptemp = NULL;
+ break;
+ }
+ }
+ if (ptemp) free(ptemp);
+ }
+#endif
+
+ 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;
+#ifdef END_RAMPING
+ channel->playing->declick_stage = 0;
+ channel->playing->declick_volume = 1.f / 256.f;
+#endif
+ channel->playing->channel_volume = channel->channelvolume;
+ channel->playing->ramp_volume[0] = 31337.0; /* special */
+ 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;
+ }
+ }
+}
+
+
+
+/* This function assumes !IT_IS_END_ROW(entry). */
+static int process_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry, int ignore_cxx)
+{
+ DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
+
+ if (sigdata->flags & IT_WAS_AN_XM)
+ process_xm_note_data(sigrenderer, entry);
+ else
+ if (process_it_note_data(sigrenderer, entry)) return 0;
+
+ return process_effects(sigrenderer, entry, ignore_cxx);
+}
+
+
+
+static int process_entry(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry, int ignore_cxx)
+{
+ IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel];
+
+ if (entry->mask & IT_ENTRY_NOTE)
+ channel->note = entry->note;
+
+ if ((entry->mask & (IT_ENTRY_NOTE|IT_ENTRY_EFFECT)) && (sigrenderer->sigdata->flags & IT_WAS_A_669)) {
+ reset_channel_effects(channel);
+ // XXX unknown
+ if (channel->playing) channel->playing->finetune = 0;
+ }
+
+ if ((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_S) {
+ /* channel->lastS was set in update_pattern_variables(). */
+ unsigned char effectvalue = channel->lastS;
+ if (effectvalue >> 4 == IT_S_NOTE_DELAY) {
+ channel->note_delay_count = effectvalue & 15;
+ if (channel->note_delay_count == 0)
+ channel->note_delay_count = 1;
+ channel->note_delay_entry = entry;
+ return 0;
+ }
+ }
+
+ return process_note_data(sigrenderer, entry, ignore_cxx);
+}
+
+
+
+static void update_tick_counts(DUMB_IT_SIGRENDERER *sigrenderer)
+{
+ int i;
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ IT_CHANNEL *channel = &sigrenderer->channel[i];
+
+ if (channel->key_off_count) {
+ channel->key_off_count--;
+ if (channel->key_off_count == 0)
+ xm_note_off(sigrenderer->sigdata, channel);
+ } else if (channel->note_cut_count) {
+ channel->note_cut_count--;
+ if (channel->note_cut_count == 0) {
+ if (sigrenderer->sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_PTM))
+ channel->volume = 0;
+ else if (channel->playing) {
+#ifdef RAMP_DOWN
+ int i;
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
+ if (!sigrenderer->playing[i]) {
+ channel->playing->declick_stage = 2;
+ sigrenderer->playing[i] = channel->playing;
+ channel->playing = NULL;
+ break;
+ }
+ }
+ if (channel->playing) {
+ free(channel->playing);
+ channel->playing = NULL;
+ }
+#else
+ free(channel->playing);
+ channel->playing = NULL;
+#endif
+ }
+ }
+ } else if (channel->note_delay_count) {
+ channel->note_delay_count--;
+ if (channel->note_delay_count == 0)
+ process_note_data(sigrenderer, channel->note_delay_entry, 0);
+ /* Don't bother checking the return value; if the note
+ * was delayed, there can't have been a speed=0.
+ */
+ }
+ }
+}
+
+
+
+static int envelope_get_y(IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe)
+{
+#if 1
+ (void)envelope; //TODO: remove the parameter
+ return pe->value;
+#else
+ int ys, ye;
+ int ts, te;
+ int t;
+
+ if (pe->next_node <= 0)
+ return envelope->node_y[0] << IT_ENVELOPE_SHIFT;
+
+ if (pe->next_node >= envelope->n_nodes)
+ return envelope->node_y[envelope->n_nodes-1] << IT_ENVELOPE_SHIFT;
+
+ ys = envelope->node_y[pe->next_node-1] << IT_ENVELOPE_SHIFT;
+ ts = envelope->node_t[pe->next_node-1];
+ te = envelope->node_t[pe->next_node];
+
+ if (ts == te)
+ return ys;
+
+ ye = envelope->node_y[pe->next_node] << IT_ENVELOPE_SHIFT;
+
+ t = pe->tick;
+
+ return ys + (ye - ys) * (t - ts) / (te - ts);
+#endif
+}
+
+
+
+#if 0
+static int it_envelope_end(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe)
+{
+ if (pe->next_node >= envelope->n_nodes)
+ return 1;
+
+ if (pe->tick < envelope->node_t[pe->next_node]) return 0;
+
+ if ((envelope->flags & IT_ENVELOPE_LOOP_ON) &&
+ envelope->loop_end >= pe->next_node &&
+ envelope->node_t[envelope->loop_end] <= pe->tick) return 0;
+
+ if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) &&
+ !(playing->flags & IT_PLAYING_SUSTAINOFF) &&
+ envelope->sus_loop_end >= pe->next_node &&
+ envelope->node_t[envelope->sus_loop_end] <= pe->tick) return 0;
+
+ if (envelope->node_t[envelope->n_nodes-1] <= pe->tick) return 1;
+
+ return 0;
+}
+#endif
+
+
+
+/* Returns 1 when fading should be initiated for a volume envelope. */
+static int update_it_envelope(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe, int flags)
+{
+ if (!(playing->enabled_envelopes & flags))
+ return 0;
+
+ ASSERT(envelope->n_nodes > 0);
+
+ if (pe->next_node <= 0)
+ pe->value = envelope->node_y[0] << IT_ENVELOPE_SHIFT;
+ else if (pe->next_node >= envelope->n_nodes) {
+ pe->value = envelope->node_y[envelope->n_nodes-1] << IT_ENVELOPE_SHIFT;
+ return 1;
+ } else {
+ int ys = envelope->node_y[pe->next_node-1] << IT_ENVELOPE_SHIFT;
+ int ts = envelope->node_t[pe->next_node-1];
+ int te = envelope->node_t[pe->next_node];
+
+ if (ts == te)
+ pe->value = ys;
+ else {
+ int ye = envelope->node_y[pe->next_node] << IT_ENVELOPE_SHIFT;
+ int t = pe->tick;
+
+ pe->value = ys + (ye - ys) * (t - ts) / (te - ts);
+ }
+ }
+
+ pe->tick++;
+ while (pe->tick >= envelope->node_t[pe->next_node]) {
+ pe->next_node++;
+ if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) {
+ if (pe->next_node > envelope->sus_loop_end) {
+ pe->next_node = envelope->sus_loop_start;
+ ASSERT(pe->next_node < envelope->n_nodes);
+ pe->tick = envelope->node_t[envelope->sus_loop_start];
+ return 0;
+ }
+ } else if (envelope->flags & IT_ENVELOPE_LOOP_ON) {
+ if (pe->next_node > envelope->loop_end) {
+ pe->next_node = envelope->loop_start;
+ ASSERT(pe->next_node < envelope->n_nodes);
+ pe->tick = envelope->node_t[envelope->loop_start];
+ return 0;
+ }
+ }
+ if (pe->next_node >= envelope->n_nodes)
+ return 0;
+ }
+ return 0;
+}
+
+
+
+static void update_it_envelopes(IT_PLAYING *playing)
+{
+ IT_ENVELOPE *envelope = &playing->env_instrument->volume_envelope;
+ IT_PLAYING_ENVELOPE *pe = &playing->volume_envelope;
+
+ if (update_it_envelope(playing, envelope, pe, IT_ENV_VOLUME)) {
+ playing->flags |= IT_PLAYING_FADING;
+ if (pe->value == 0)
+ playing->flags |= IT_PLAYING_DEAD;
+ }
+
+ update_it_envelope(playing, &playing->env_instrument->pan_envelope, &playing->pan_envelope, IT_ENV_PANNING);
+ update_it_envelope(playing, &playing->env_instrument->pitch_envelope, &playing->pitch_envelope, IT_ENV_PITCH);
+}
+
+
+
+static int xm_envelope_is_sustaining(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe)
+{
+ if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF))
+ if (envelope->sus_loop_start < envelope->n_nodes)
+ if (pe->tick == envelope->node_t[envelope->sus_loop_start])
+ return 1;
+ return 0;
+}
+
+
+
+static void update_xm_envelope(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe)
+{
+ if (!(envelope->flags & IT_ENVELOPE_ON))
+ return;
+
+ if (xm_envelope_is_sustaining(playing, envelope, pe))
+ return;
+
+ if (pe->tick >= envelope->node_t[envelope->n_nodes-1])
+ return;
+
+ pe->tick++;
+
+ /* pe->next_node must be kept up to date for envelope_get_y(). */
+ while (pe->tick > envelope->node_t[pe->next_node])
+ pe->next_node++;
+
+ if ((envelope->flags & IT_ENVELOPE_LOOP_ON) && envelope->loop_end < envelope->n_nodes) {
+ if (pe->tick == envelope->node_t[envelope->loop_end]) {
+ pe->next_node = MID(0, envelope->loop_start, envelope->n_nodes - 1);
+ pe->tick = envelope->node_t[pe->next_node];
+ }
+ }
+
+ xm_envelope_calculate_value(envelope, pe);
+}
+
+
+
+static void update_xm_envelopes(IT_PLAYING *playing)
+{
+ update_xm_envelope(playing, &playing->env_instrument->volume_envelope, &playing->volume_envelope);
+ update_xm_envelope(playing, &playing->env_instrument->pan_envelope, &playing->pan_envelope);
+}
+
+
+
+static void update_fadeout(DUMB_IT_SIGDATA *sigdata, IT_PLAYING *playing)
+{
+ if (playing->flags & IT_PLAYING_FADING) {
+ playing->fadeoutcount -= playing->env_instrument->fadeout;
+ if (playing->fadeoutcount <= 0) {
+ playing->fadeoutcount = 0;
+ if (!(sigdata->flags & IT_WAS_AN_XM))
+ playing->flags |= IT_PLAYING_DEAD;
+ }
+ }
+}
+
+static int apply_pan_envelope(IT_PLAYING *playing);
+static float calculate_volume(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float volume);
+
+static void playing_volume_setup(DUMB_IT_SIGRENDERER * sigrenderer, IT_PLAYING * playing, float invt2g)
+{
+ DUMB_IT_SIGDATA * sigdata = sigrenderer->sigdata;
+ int pan;
+ float volume, vol, span;
+
+ if ((sigrenderer->n_channels == 2) && (sigdata->flags & IT_STEREO)) {
+ pan = apply_pan_envelope(playing);
+ if ((sigdata->flags & IT_WAS_AN_S3M) && IT_IS_SURROUND_SHIFTED(pan)) {
+ volume = -1.0f * (float)(pan) * (1.0f / (64.0f * 256.0f));
+ } else {
+ volume = 1.0f;
+ }
+ span = (pan - (32<<8)) * sigdata->pan_separation * (1.0f / ((32<<8) * 128));
+ vol = volume;
+ if (!IT_IS_SURROUND_SHIFTED(pan)) vol *= 1.0f - span;
+ playing->float_volume[0] = vol;
+ vol = -vol;
+ if (!IT_IS_SURROUND_SHIFTED(pan)) vol += 2.0f * volume;
+ playing->float_volume[1] = vol;
+ } else {
+ if ((sigdata->flags & IT_STEREO) && (playing->sample->flags & IT_SAMPLE_STEREO)) {
+ pan = apply_pan_envelope(playing);
+ span = (pan - (32<<8)) * sigdata->pan_separation * (1.0f / ((32<<8) * 128));
+ vol = 0.5f;
+ if (!IT_IS_SURROUND_SHIFTED(pan)) vol *= 1.0f - span;
+ playing->float_volume[0] = vol;
+ if (!IT_IS_SURROUND_SHIFTED(pan)) vol = 2.0f - vol;
+ playing->float_volume[1] = vol;
+ } else {
+ playing->float_volume[0] = 1.0f;
+ playing->float_volume[1] = 1.0f;
+ }
+ }
+
+ vol = calculate_volume(sigrenderer, playing, 1.0f);
+ playing->float_volume[0] *= vol;
+ playing->float_volume[1] *= vol;
+
+ if (!sigrenderer->ramp_style || playing->ramp_volume[0] == 31337.0) {
+ playing->ramp_volume[0] = playing->float_volume[0];
+ playing->ramp_volume[1] = playing->float_volume[1];
+ playing->ramp_delta[0] = 0;
+ playing->ramp_delta[1] = 0;
+ } else {
+ playing->ramp_delta[0] = invt2g * (playing->float_volume[0] - playing->ramp_volume[0]);
+ playing->ramp_delta[1] = invt2g * (playing->float_volume[1] - playing->ramp_volume[1]);
+ }
+}
+
+static void process_playing(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float invt2g)
+{
+ DUMB_IT_SIGDATA * sigdata = sigrenderer->sigdata;
+
+ if (playing->instrument) {
+ if (sigdata->flags & IT_WAS_AN_XM)
+ update_xm_envelopes(playing);
+ else
+ update_it_envelopes(playing);
+ update_fadeout(sigdata, playing);
+ }
+
+ playing_volume_setup(sigrenderer, playing, invt2g);
+
+ if (sigdata->flags & IT_WAS_AN_XM) {
+ /* 'depth' is used to store the tick number for XM files. */
+ if (playing->sample_vibrato_depth < playing->sample->vibrato_rate)
+ playing->sample_vibrato_depth++;
+ } else {
+ playing->sample_vibrato_depth += playing->sample->vibrato_rate;
+ if (playing->sample_vibrato_depth > playing->sample->vibrato_depth << 8)
+ playing->sample_vibrato_depth = playing->sample->vibrato_depth << 8;
+ }
+
+ playing->sample_vibrato_time += playing->sample->vibrato_speed;
+}
+
+//static float log2(float x) {return (float)log(x)/(float)log(2.0f);}
+#ifndef __linux__
+static inline float log2(float x) {return (float)log(x)/(float)log(2.0f);}
+#endif
+
+static int delta_to_note(float delta, int base)
+{
+ float note;
+ note = log2(delta * 65536.f / (float)base)*12.0f+60.5f;
+ if (note > 119) note = 119;
+ else if (note < 0) note = 0;
+ return (int)note;
+}
+
+// Period table for Protracker octaves 0-5:
+static const unsigned short ProTrackerPeriodTable[6*12] =
+{
+ 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907,
+ 856,808,762,720,678,640,604,570,538,508,480,453,
+ 428,404,381,360,339,320,302,285,269,254,240,226,
+ 214,202,190,180,170,160,151,143,135,127,120,113,
+ 107,101,95,90,85,80,75,71,67,63,60,56,
+ 53,50,47,45,42,40,37,35,33,31,30,28
+};
+
+
+static const unsigned short ProTrackerTunedPeriods[16*12] =
+{
+ 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907,
+ 1700,1604,1514,1430,1348,1274,1202,1134,1070,1010,954,900,
+ 1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,894,
+ 1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,888,
+ 1664,1570,1482,1398,1320,1246,1176,1110,1048,990,934,882,
+ 1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,874,
+ 1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,868,
+ 1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914,862,
+ 1814,1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,
+ 1800,1700,1604,1514,1430,1350,1272,1202,1134,1070,1010,954,
+ 1788,1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,
+ 1774,1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,
+ 1762,1664,1570,1482,1398,1320,1246,1176,1110,1048,988,934,
+ 1750,1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,
+ 1736,1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,
+ 1724,1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914
+};
+
+static void process_all_playing(DUMB_IT_SIGRENDERER *sigrenderer)
+{
+ DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
+ int i;
+
+ float invt2g = 1.0f / ((float)TICK_TIME_DIVIDEND / (float)sigrenderer->tempo);
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ IT_CHANNEL *channel = &sigrenderer->channel[i];
+ IT_PLAYING *playing = channel->playing;
+
+ if (playing) {
+ int vibrato_shift;
+ switch (playing->vibrato_waveform)
+ {
+ default:
+ vibrato_shift = it_sine[playing->vibrato_time];
+ break;
+ case 1:
+ vibrato_shift = it_sawtooth[playing->vibrato_time];
+ break;
+ case 2:
+ vibrato_shift = it_squarewave[playing->vibrato_time];
+ break;
+ case 3:
+ vibrato_shift = (rand() % 129) - 64;
+ break;
+ case 4:
+ vibrato_shift = it_xm_squarewave[playing->vibrato_time];
+ break;
+ case 5:
+ vibrato_shift = it_xm_ramp[playing->vibrato_time];
+ break;
+ case 6:
+ vibrato_shift = it_xm_ramp[255-playing->vibrato_time];
+ break;
+ }
+ vibrato_shift *= playing->vibrato_n;
+ vibrato_shift *= playing->vibrato_depth;
+ vibrato_shift >>= 4;
+
+ if (sigdata->flags & IT_OLD_EFFECTS)
+ vibrato_shift = -vibrato_shift;
+
+ playing->volume = channel->volume;
+ playing->pan = channel->truepan;
+
+ if (playing->volume_offset) {
+ playing->volume += (playing->volume_offset * playing->volume) >> 7;
+ if (playing->volume > 64) {
+ if (playing->volume_offset < 0) playing->volume = 0;
+ else playing->volume = 64;
+ }
+ }
+
+ if (playing->panning_offset && !IT_IS_SURROUND_SHIFTED(playing->pan)) {
+ playing->pan += playing->panning_offset << IT_ENVELOPE_SHIFT;
+ if (playing->pan > 64 << IT_ENVELOPE_SHIFT) {
+ if (playing->panning_offset < 0) playing->pan = 0;
+ else playing->pan = 64 << IT_ENVELOPE_SHIFT;
+ }
+ }
+
+ if (sigdata->flags & IT_LINEAR_SLIDES) {
+ int currpitch = ((playing->note - 60) << 8) + playing->slide
+ + vibrato_shift
+ + playing->finetune;
+
+ /* We add a feature here, which is that of keeping the pitch
+ * within range. Otherwise it crashes. Trust me. It happened.
+ * The limit 32768 gives almost 11 octaves either way.
+ */
+ if (currpitch < -32768)
+ currpitch = -32768;
+ else if (currpitch > 32767)
+ currpitch = 32767;
+
+ playing->delta = (float)pow(DUMB_PITCH_BASE, currpitch);
+ playing->delta *= playing->sample->C5_speed * (1.f / 65536.0f);
+ } else {
+ int slide = playing->slide + vibrato_shift;
+
+ playing->delta = (float)pow(DUMB_PITCH_BASE, ((60 - playing->note) << 8) - playing->finetune );
+ /* playing->delta is 1.0 for C-5, 0.5 for C-6, etc. */
+
+ playing->delta *= 1.0f / playing->sample->C5_speed;
+
+ playing->delta -= slide / AMIGA_DIVISOR;
+
+ if (playing->delta < (1.0f / 65536.0f) / 32768.0f) {
+ // Should XM notes die if Amiga slides go out of range?
+ playing->flags |= IT_PLAYING_DEAD;
+ playing->delta = 1. / 32768.;
+ continue;
+ }
+
+ playing->delta = (1.0f / 65536.0f) / playing->delta;
+ }
+
+ if (playing->channel->glissando && playing->channel->toneporta && playing->channel->destnote < 120) {
+ playing->delta = (float)pow(DUMB_SEMITONE_BASE, delta_to_note(playing->delta, playing->sample->C5_speed) - 60)
+ * playing->sample->C5_speed * (1.f / 65536.f);
+ }
+
+ /*
+ if ( channel->arpeggio ) { // another FT2 bug...
+ if ((sigdata->flags & (IT_LINEAR_SLIDES|IT_WAS_AN_XM|IT_WAS_A_MOD)) == (IT_WAS_AN_XM|IT_LINEAR_SLIDES) &&
+ playing->flags & IT_PLAYING_SUSTAINOFF)
+ {
+ if ( channel->arpeggio > 0xFF )
+ playing->delta = playing->sample->C5_speed * (1.f / 65536.f);
+ }
+ else*/ playing->delta *= (float)pow(DUMB_SEMITONE_BASE, channel->arpeggio >> 8);/*
+ }*/
+
+ playing->filter_cutoff = channel->filter_cutoff;
+ playing->filter_resonance = channel->filter_resonance;
+ }
+ }
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ if (sigrenderer->channel[i].playing) {
+ process_playing(sigrenderer, sigrenderer->channel[i].playing, invt2g);
+ if (!(sigdata->flags & IT_WAS_AN_XM)) {
+ //if ((sigrenderer->channel[i].playing->flags & (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) == (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) {
+ // This change was made so Gxx would work correctly when a note faded out or whatever. Let's hope nothing else was broken by it.
+ if (sigrenderer->channel[i].playing->flags & IT_PLAYING_DEAD) {
+ free(sigrenderer->channel[i].playing);
+ sigrenderer->channel[i].playing = NULL;
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
+ if (sigrenderer->playing[i]) {
+ process_playing(sigrenderer, sigrenderer->playing[i], invt2g);
+ if (sigrenderer->playing[i]->flags & IT_PLAYING_DEAD) {
+ free(sigrenderer->playing[i]);
+ sigrenderer->playing[i] = NULL;
+ }
+ }
+ }
+}
+
+
+
+static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer)
+{
+ DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata;
+
+ // Set note vol/freq to vol/freq set for each channel
+
+ if (sigrenderer->speed && --sigrenderer->tick == 0) {
+ reset_tick_counts(sigrenderer);
+ sigrenderer->tick = sigrenderer->speed;
+ sigrenderer->rowcount--;
+ if (sigrenderer->rowcount == 0) {
+ sigrenderer->rowcount = 1;
+
+#ifdef BIT_ARRAY_BULLSHIT
+ if (sigrenderer->n_rows)
+ {
+#if 1
+ /*
+ if (bit_array_test(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row))
+ {
+ if (sigrenderer->callbacks->loop) {
+ if ((*sigrenderer->callbacks->loop)(sigrenderer->callbacks->loop_data))
+ return 1;
+ bit_array_reset(sigrenderer->played);
+ if (sigrenderer->speed == 0)
+ goto speed0; /* I love goto *
+ }
+ }
+ */
+#endif
+ bit_array_set(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row);
+ {
+ int n;
+ for (n = 0; n < DUMB_IT_N_CHANNELS; n++)
+ {
+ IT_CHANNEL * channel = &sigrenderer->channel[n];
+ if (channel->played_patjump)
+ {
+ if (channel->played_patjump_order == sigrenderer->order)
+ {
+ bit_array_set(channel->played_patjump, sigrenderer->row);
+ }
+ /*
+ else if ((channel->played_patjump_order & 0x7FFF) == sigrenderer->order)
+ {
+ channel->played_patjump_order |= 0x4000;
+ }
+ else if ((channel->played_patjump_order & 0x3FFF) == sigrenderer->order)
+ {
+ if ((sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD)) == IT_WAS_AN_XM)
+ {
+ /* joy, was XM, pattern loop bug triggered break to row in same order
+ bit_array_mask(sigrenderer->played, channel->played_patjump, sigrenderer->order * 256);
+ }
+ bit_array_destroy(channel->played_patjump);
+ channel->played_patjump = 0;
+ channel->played_patjump_order = 0xFFFE;
+ }
+ */
+ else
+ {
+ bit_array_destroy(channel->played_patjump);
+ channel->played_patjump = 0;
+ channel->played_patjump_order = 0xFFFE;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ sigrenderer->processrow++;
+
+ if (sigrenderer->processrow >= sigrenderer->n_rows) {
+ IT_PATTERN *pattern;
+ int n;
+ int processorder = sigrenderer->processorder;
+
+ if ((sigrenderer->processrow|0xC00) == 0xFFFE + 1) { /* It was incremented above! */
+ sigrenderer->processrow = sigrenderer->breakrow;
+ sigrenderer->breakrow = 0;
+ for (n = 0; n < DUMB_IT_N_CHANNELS; n++) sigrenderer->channel[n].pat_loop_end_row = 0;
+ } else
+ sigrenderer->processrow = sigrenderer->breakrow;
+
+ if (sigrenderer->processorder == 0xFFFF)
+ sigrenderer->processorder = sigrenderer->order - 1;
+
+ for (;;) {
+ sigrenderer->processorder++;
+
+ if (sigrenderer->processorder >= sigdata->n_orders) {
+ sigrenderer->processorder = sigrenderer->restart_position;
+ if (sigrenderer->processorder >= sigdata->n_orders) {
+ /* Restarting beyond end. We'll loop for now. */
+ sigrenderer->processorder = -1;
+ continue;
+ }
+ }
+
+ n = sigdata->order[sigrenderer->processorder];
+
+ if (n < sigdata->n_patterns)
+ break;
+
+#ifdef INVALID_ORDERS_END_SONG
+ if (n != IT_ORDER_SKIP)
+#else
+ if (n == IT_ORDER_END)
+#endif
+ {
+ sigrenderer->processorder = sigrenderer->restart_position - 1;
+ }
+ }
+
+ pattern = &sigdata->pattern[n];
+
+ n = sigrenderer->n_rows;
+ sigrenderer->n_rows = pattern->n_rows;
+
+ if (sigrenderer->processrow >= sigrenderer->n_rows)
+ sigrenderer->processrow = 0;
+
+/** WARNING - everything pertaining to a new pattern initialised? */
+
+ sigrenderer->entry = sigrenderer->entry_start = pattern->entry;
+ sigrenderer->entry_end = sigrenderer->entry + pattern->n_entries;
+
+ /* If n_rows was 0, we're only just starting. Don't do anything weird here. */
+ /* added: process row check, for break to row spooniness */
+ if (n && (processorder == 0xFFFF ? sigrenderer->order > sigrenderer->processorder : sigrenderer->order >= sigrenderer->processorder)
+#ifdef BIT_ARRAY_BULLSHIT
+ && bit_array_test(sigrenderer->played, sigrenderer->processorder * 256 + sigrenderer->processrow)
+#endif
+ ) {
+ if (sigrenderer->callbacks->loop) {
+ if ((*sigrenderer->callbacks->loop)(sigrenderer->callbacks->loop_data))
+ return 1;
+#ifdef BIT_ARRAY_BULLSHIT
+ bit_array_reset(sigrenderer->played);
+#endif
+ if (sigrenderer->speed == 0)
+ goto speed0; /* I love goto */
+ }
+ }
+ sigrenderer->order = sigrenderer->processorder;
+
+ n = sigrenderer->processrow;
+ while (n) {
+ while (sigrenderer->entry < sigrenderer->entry_end) {
+ if (IT_IS_END_ROW(sigrenderer->entry)) {
+ sigrenderer->entry++;
+ break;
+ }
+ sigrenderer->entry++;
+ }
+ n--;
+ }
+ sigrenderer->row = sigrenderer->processrow;
+ } else {
+ if (sigrenderer->entry) {
+ while (sigrenderer->entry < sigrenderer->entry_end) {
+ if (IT_IS_END_ROW(sigrenderer->entry)) {
+ sigrenderer->entry++;
+ break;
+ }
+ sigrenderer->entry++;
+ }
+ sigrenderer->row++;
+ } else {
+#ifdef BIT_ARRAY_BULLSHIT
+ bit_array_clear(sigrenderer->played, sigrenderer->order * 256);
+#endif
+ sigrenderer->entry = sigrenderer->entry_start;
+ sigrenderer->row = 0;
+ }
+ }
+
+ if (!(sigdata->flags & IT_WAS_A_669))
+ reset_effects(sigrenderer);
+
+ {
+ IT_ENTRY *entry = sigrenderer->entry;
+ int ignore_cxx = 0;
+
+ while (entry < sigrenderer->entry_end && !IT_IS_END_ROW(entry))
+ ignore_cxx |= update_pattern_variables(sigrenderer, entry++);
+
+ entry = sigrenderer->entry;
+
+ while (entry < sigrenderer->entry_end && !IT_IS_END_ROW(entry))
+ if (process_entry(sigrenderer, entry++, sigdata->flags & IT_WAS_AN_XM ? 0 : ignore_cxx))
+ return 1;
+ }
+
+ if (!(sigdata->flags & IT_OLD_EFFECTS))
+ update_smooth_effects(sigrenderer);
+ } else {
+ {
+ IT_ENTRY *entry = sigrenderer->entry;
+
+ while (entry < sigrenderer->entry_end && !IT_IS_END_ROW(entry)) {
+ if (entry->mask & IT_ENTRY_EFFECT && entry->effect != IT_SET_SAMPLE_OFFSET)
+ process_effects(sigrenderer, entry, 0);
+ /* Don't bother checking the return value; if there
+ * was a pattern delay, there can't be a speed=0.
+ */
+ entry++;
+ }
+ }
+
+ update_effects(sigrenderer);
+ }
+ } else {
+ speed0:
+ update_effects(sigrenderer);
+ update_tick_counts(sigrenderer);
+ }
+
+ if (sigrenderer->globalvolume == 0) {
+ if (sigrenderer->callbacks->global_volume_zero) {
+ LONG_LONG t = sigrenderer->gvz_sub_time + ((LONG_LONG)TICK_TIME_DIVIDEND << 16) / sigrenderer->tempo;
+ sigrenderer->gvz_time += (int)(t >> 16);
+ sigrenderer->gvz_sub_time = (int)t & 65535;
+ if (sigrenderer->gvz_time >= 65536 * 12) {
+ if ((*sigrenderer->callbacks->global_volume_zero)(sigrenderer->callbacks->global_volume_zero_data))
+ return 1;
+ }
+ }
+ } else {
+ if (sigrenderer->callbacks->global_volume_zero) {
+ sigrenderer->gvz_time = 0;
+ sigrenderer->gvz_sub_time = 0;
+ }
+ }
+
+ process_all_playing(sigrenderer);
+
+ {
+ LONG_LONG t = sigrenderer->sub_time_left + ((LONG_LONG)TICK_TIME_DIVIDEND << 16) / sigrenderer->tempo;
+ sigrenderer->time_left += (int)(t >> 16);
+ sigrenderer->sub_time_left = (int)t & 65535;
+ }
+
+ return 0;
+}
+
+
+
+int dumb_it_max_to_mix = 64;
+
+static const int aiMODVol[] =
+{
+ 0,
+ 16, 24, 32, 48, 64, 80, 96, 112,
+ 128, 144, 160, 176, 192, 208, 224, 240,
+ 256, 272, 288, 304, 320, 336, 352, 368,
+ 384, 400, 416, 432, 448, 464, 480, 496,
+ 529, 545, 561, 577, 593, 609, 625, 641,
+ 657, 673, 689, 705, 721, 737, 753, 769,
+ 785, 801, 817, 833, 849, 865, 881, 897,
+ 913, 929, 945, 961, 977, 993, 1009, 1024
+};
+
+static const int aiPTMVolScaled[] =
+{
+ 0,
+ 31, 54, 73, 96, 111, 130, 153, 172,
+ 191, 206, 222, 237, 252, 275, 298, 317,
+ 336, 351, 370, 386, 401, 416, 428, 443,
+ 454, 466, 477, 489, 512, 531, 553, 573,
+ 592, 611, 626, 645, 660, 679, 695, 710,
+ 725, 740, 756, 767, 782, 798, 809, 820,
+ 836, 847, 859, 870, 881, 897, 908, 916,
+ 927, 939, 950, 962, 969, 983, 1005, 1024
+};
+
+static float calculate_volume(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float volume)
+{
+ if (volume != 0) {
+ int vol;
+
+ if (playing->channel->flags & IT_CHANNEL_MUTED)
+ return 0;
+
+ if ((playing->channel->tremor_time & 192) == 128)
+ return 0;
+
+ switch (playing->tremolo_waveform)
+ {
+ default:
+ vol = it_sine[playing->tremolo_time];
+ break;
+ case 1:
+ vol = it_sawtooth[playing->tremolo_time];
+ break;
+ case 2:
+ vol = it_squarewave[playing->tremolo_time];
+ break;
+ case 3:
+ vol = (rand() % 129) - 64;
+ break;
+ case 4:
+ vol = it_xm_squarewave[playing->vibrato_time];
+ break;
+ case 5:
+ vol = it_xm_ramp[playing->vibrato_time];
+ break;
+ case 6:
+ vol = it_xm_ramp[255-playing->vibrato_time];
+ break;
+ }
+ vol *= playing->tremolo_depth;
+
+ vol = (playing->volume << 5) + vol;
+
+ if (vol <= 0)
+ return 0;
+
+ if (vol > 64 << 5)
+ vol = 64 << 5;
+
+ if ( sigrenderer->sigdata->flags & IT_WAS_A_PTM )
+ {
+ int v = aiPTMVolScaled[ vol >> 5 ];
+ if ( vol < 64 << 5 )
+ {
+ int f = vol & ( ( 1 << 5 ) - 1 );
+ int f2 = ( 1 << 5 ) - f;
+ int v2 = aiPTMVolScaled[ ( vol >> 5 ) + 1 ];
+ v = ( v * f2 + v2 * f ) >> 5;
+ }
+ vol = v << 1;
+ }
+
+ volume *= vol; /* 64 << 5 */
+ volume *= playing->sample->global_volume; /* 64 */
+ volume *= playing->channel_volume; /* 64 */
+ volume *= sigrenderer->globalvolume; /* 128 */
+ volume *= sigrenderer->sigdata->mixing_volume; /* 128 */
+ volume *= 1.0f / ((64 << 5) * 64.0f * 64.0f * 128.0f * 128.0f);
+
+ if (volume && playing->instrument) {
+ if (playing->enabled_envelopes & IT_ENV_VOLUME) {
+ volume *= envelope_get_y(&playing->env_instrument->volume_envelope, &playing->volume_envelope);
+ volume *= 1.0f / (64 << IT_ENVELOPE_SHIFT);
+ }
+ volume *= playing->instrument->global_volume; /* 128 */
+ volume *= playing->fadeoutcount; /* 1024 */
+ volume *= 1.0f / (128.0f * 1024.0f);
+ }
+ }
+
+ return volume;
+}
+
+
+
+static int apply_pan_envelope(IT_PLAYING *playing)
+{
+ if (playing->pan <= 64 << IT_ENVELOPE_SHIFT) {
+ int pan;
+ if (playing->panbrello_depth) {
+ switch (playing->panbrello_waveform) {
+ default:
+ pan = it_sine[playing->panbrello_time];
+ break;
+ case 1:
+ pan = it_sawtooth[playing->panbrello_time];
+ break;
+ case 2:
+ pan = it_squarewave[playing->panbrello_time];
+ break;
+ case 3:
+ pan = playing->panbrello_random;
+ break;
+ }
+ pan *= playing->panbrello_depth << 3;
+
+ pan += playing->pan;
+ if (pan < 0) pan = 0;
+ else if (pan > 64 << IT_ENVELOPE_SHIFT) pan = 64 << IT_ENVELOPE_SHIFT;
+ } else {
+ pan = playing->pan;
+ }
+
+ if (playing->env_instrument && (playing->enabled_envelopes & IT_ENV_PANNING)) {
+ int p = envelope_get_y(&playing->env_instrument->pan_envelope, &playing->pan_envelope);
+ if (pan > 32 << IT_ENVELOPE_SHIFT)
+ p *= (64 << IT_ENVELOPE_SHIFT) - pan;
+ else
+ p *= pan;
+ pan += p >> (5 + IT_ENVELOPE_SHIFT);
+ }
+ return pan;
+ }
+ return playing->pan;
+}
+
+
+
+/* Note: if a click remover is provided, and store_end_sample is set, then
+ * the end point will be computed twice. This situation should not arise.
+ */
+static long render_playing(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float volume, float main_delta, float delta, long pos, long size, sample_t **samples, int store_end_sample, int *left_to_mix, int cr_record_which)
+{
+ int bits;
+
+ long size_rendered;
+
+ DUMB_VOLUME_RAMP_INFO lvol, rvol;
+
+ if (playing->flags & IT_PLAYING_DEAD)
+ return 0;
+
+ if (*left_to_mix <= 0)
+ volume = 0;
+
+#ifndef END_RAMPING
+ {
+ int quality = sigrenderer->resampling_quality;
+ if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality)
+ quality = playing->sample->max_resampling_quality;
+ playing->resampler.quality = quality;
+ }
+#endif
+
+ bits = playing->sample->flags & IT_SAMPLE_16BIT ? 16 : 8;
+
+ if (volume == 0) {
+ if (playing->sample->flags & IT_SAMPLE_STEREO)
+ size_rendered = dumb_resample_n_2_1(bits, &playing->resampler, NULL, size, 0, 0, delta);
+ else
+ size_rendered = dumb_resample_n_1_1(bits, &playing->resampler, NULL, size, 0, delta);
+ } else {
+ lvol.volume = playing->ramp_volume [0];
+ rvol.volume = playing->ramp_volume [1];
+ lvol.delta = playing->ramp_delta [0] * main_delta;
+ rvol.delta = playing->ramp_delta [1] * main_delta;
+ lvol.target = playing->float_volume [0];
+ rvol.target = playing->float_volume [1];
+ rvol.mix = lvol.mix = volume;
+ if (sigrenderer->n_channels == 2) {
+ if (playing->sample->flags & IT_SAMPLE_STEREO) {
+ if ((cr_record_which & 1) && sigrenderer->click_remover) {
+ sample_t click[2];
+ dumb_resample_get_current_sample_n_2_2(bits, &playing->resampler, &lvol, &rvol, click);
+ dumb_record_click(sigrenderer->click_remover[0], pos, click[0]);
+ dumb_record_click(sigrenderer->click_remover[1], pos, click[1]);
+ }
+ size_rendered = dumb_resample_n_2_2(bits, &playing->resampler, samples[0] + pos*2, size, &lvol, &rvol, delta);
+ if (store_end_sample) {
+ sample_t click[2];
+ dumb_resample_get_current_sample_n_2_2(bits, &playing->resampler, &lvol, &rvol, click);
+ samples[0][(pos + size_rendered) * 2] = click[0];
+ samples[0][(pos + size_rendered) * 2 + 1] = click[1];
+ }
+ if ((cr_record_which & 2) && sigrenderer->click_remover) {
+ sample_t click[2];
+ dumb_resample_get_current_sample_n_2_2(bits, &playing->resampler, &lvol, &rvol, click);
+ dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click[0]);
+ dumb_record_click(sigrenderer->click_remover[1], pos + size_rendered, -click[1]);
+ }
+ } else {
+ if ((cr_record_which & 1) && sigrenderer->click_remover) {
+ sample_t click[2];
+ dumb_resample_get_current_sample_n_1_2(bits, &playing->resampler, &lvol, &rvol, click);
+ dumb_record_click(sigrenderer->click_remover[0], pos, click[0]);
+ dumb_record_click(sigrenderer->click_remover[1], pos, click[1]);
+ }
+ size_rendered = dumb_resample_n_1_2(bits, &playing->resampler, samples[0] + pos*2, size, &lvol, &rvol, delta);
+ if (store_end_sample) {
+ sample_t click[2];
+ dumb_resample_get_current_sample_n_1_2(bits, &playing->resampler, &lvol, &rvol, click);
+ samples[0][(pos + size_rendered) * 2] = click[0];
+ samples[0][(pos + size_rendered) * 2 + 1] = click[1];
+ }
+ if ((cr_record_which & 2) && sigrenderer->click_remover) {
+ sample_t click[2];
+ dumb_resample_get_current_sample_n_1_2(bits, &playing->resampler, &lvol, &rvol, click);
+ dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click[0]);
+ dumb_record_click(sigrenderer->click_remover[1], pos + size_rendered, -click[1]);
+ }
+ }
+ } else {
+ if (playing->sample->flags & IT_SAMPLE_STEREO) {
+ if ((cr_record_which & 1) && sigrenderer->click_remover) {
+ sample_t click;
+ dumb_resample_get_current_sample_n_2_1(bits, &playing->resampler, &lvol, &rvol, &click);
+ dumb_record_click(sigrenderer->click_remover[0], pos, click);
+ }
+ size_rendered = dumb_resample_n_2_1(bits, &playing->resampler, samples[0] + pos, size, &lvol, &rvol, delta);
+ if (store_end_sample)
+ dumb_resample_get_current_sample_n_2_1(bits, &playing->resampler, &lvol, &rvol, &samples[0][pos + size_rendered]);
+ if ((cr_record_which & 2) && sigrenderer->click_remover) {
+ sample_t click;
+ dumb_resample_get_current_sample_n_2_1(bits, &playing->resampler, &lvol, &rvol, &click);
+ dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click);
+ }
+ } else {
+ if ((cr_record_which & 1) && sigrenderer->click_remover) {
+ sample_t click;
+ dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, &lvol, &click);
+ dumb_record_click(sigrenderer->click_remover[0], pos, click);
+ }
+ size_rendered = dumb_resample_n_1_1(bits, &playing->resampler, samples[0] + pos, size, &lvol, delta);
+ if (store_end_sample)
+ dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, &lvol, &samples[0][pos + size_rendered]);
+ if ((cr_record_which & 2) && sigrenderer->click_remover) {
+ sample_t click;
+ dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, &lvol, &click);
+ dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click);
+ }
+ }
+ }
+ playing->ramp_volume [0] = lvol.volume;
+ playing->ramp_volume [1] = rvol.volume;
+ (*left_to_mix)--;
+ }
+
+ if (playing->resampler.dir == 0)
+ playing->flags |= IT_PLAYING_DEAD;
+
+ return size_rendered;
+}
+
+#ifdef END_RAMPING
+#if 1
+static long render_playing_part(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, DUMB_VOLUME_RAMP_INFO * lvol, DUMB_VOLUME_RAMP_INFO * rvol, int bits, float delta, long pos, long size, sample_t **samples, int store_end_sample, int cr_record_which)
+{
+ long size_rendered = 0;
+
+ if (sigrenderer->n_channels == 2) {
+ if (playing->sample->flags & IT_SAMPLE_STEREO) {
+ if ((cr_record_which & 1) && sigrenderer->click_remover) {
+ sample_t click[2];
+ dumb_resample_get_current_sample_n_2_2(bits, &playing->resampler, lvol, rvol, click);
+ dumb_record_click(sigrenderer->click_remover[0], pos, click[0]);
+ dumb_record_click(sigrenderer->click_remover[1], pos, click[1]);
+ }
+ size_rendered = dumb_resample_n_2_2(bits, &playing->resampler, samples[0] + pos*2, size, lvol, rvol, delta);
+ if (store_end_sample) {
+ sample_t click[2];
+ dumb_resample_get_current_sample_n_2_2(bits, &playing->resampler, lvol, rvol, click);
+ samples[0][(pos + size_rendered) * 2] = click[0];
+ samples[0][(pos + size_rendered) * 2 + 1] = click[1];
+ }
+ if ((cr_record_which & 2) && sigrenderer->click_remover) {
+ sample_t click[2];
+ dumb_resample_get_current_sample_n_2_2(bits, &playing->resampler, lvol, rvol, click);
+ dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click[0]);
+ dumb_record_click(sigrenderer->click_remover[1], pos + size_rendered, -click[1]);
+ }
+ } else {
+ if ((cr_record_which & 1) && sigrenderer->click_remover) {
+ sample_t click[2];
+ dumb_resample_get_current_sample_n_1_2(bits, &playing->resampler, lvol, rvol, click);
+ dumb_record_click(sigrenderer->click_remover[0], pos, click[0]);
+ dumb_record_click(sigrenderer->click_remover[1], pos, click[1]);
+ }
+ size_rendered = dumb_resample_n_1_2(bits, &playing->resampler, samples[0] + pos*2, size, lvol, rvol, delta);
+ if (store_end_sample) {
+ sample_t click[2];
+ dumb_resample_get_current_sample_n_1_2(bits, &playing->resampler, lvol, rvol, click);
+ samples[0][(pos + size_rendered) * 2] = click[0];
+ samples[0][(pos + size_rendered) * 2 + 1] = click[1];
+ }
+ if ((cr_record_which & 2) && sigrenderer->click_remover) {
+ sample_t click[2];
+ dumb_resample_get_current_sample_n_1_2(bits, &playing->resampler, lvol, rvol, click);
+ dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click[0]);
+ dumb_record_click(sigrenderer->click_remover[1], pos + size_rendered, -click[1]);
+ }
+ }
+ } else {
+ if (playing->sample->flags & IT_SAMPLE_STEREO) {
+ if ((cr_record_which & 1) && sigrenderer->click_remover) {
+ sample_t click;
+ dumb_resample_get_current_sample_n_2_1(bits, &playing->resampler, lvol, rvol, &click);
+ dumb_record_click(sigrenderer->click_remover[0], pos, click);
+ }
+ size_rendered = dumb_resample_n_2_1(bits, &playing->resampler, samples[0] + pos, size, lvol, rvol, delta);
+ if (store_end_sample)
+ dumb_resample_get_current_sample_n_2_1(bits, &playing->resampler, lvol, rvol, &samples[0][pos + size_rendered]);
+ if ((cr_record_which & 2) && sigrenderer->click_remover) {
+ sample_t click;
+ dumb_resample_get_current_sample_n_2_1(bits, &playing->resampler, lvol, rvol, &click);
+ dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click);
+ }
+ } else {
+ if ((cr_record_which & 1) && sigrenderer->click_remover) {
+ sample_t click;
+ dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, lvol, &click);
+ dumb_record_click(sigrenderer->click_remover[0], pos, click);
+ }
+ size_rendered = dumb_resample_n_1_1(bits, &playing->resampler, samples[0] + pos, size, lvol, delta);
+ if (store_end_sample)
+ dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, lvol, &samples[0][pos + size_rendered]);
+ if ((cr_record_which & 2) && sigrenderer->click_remover) {
+ sample_t click;
+ dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, lvol, &click);
+ dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click);
+ }
+ }
+ }
+ return size_rendered;
+}
+
+static long render_playing_ramp(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float volume, float main_delta, float delta, long pos, long size, sample_t **samples, int store_end_sample, int *left_to_mix, int ramp_style)
+{
+ int bits;
+
+ long size_rendered;
+
+ DUMB_VOLUME_RAMP_INFO lvol, rvol;
+
+ if (!size) return 0;
+
+ if (playing->flags & IT_PLAYING_DEAD)
+ return 0;
+
+ if (*left_to_mix <= 0)
+ volume = 0;
+
+ {
+ int quality = sigrenderer->resampling_quality;
+ if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality)
+ quality = playing->sample->max_resampling_quality;
+ playing->resampler.quality = quality;
+ }
+
+ bits = playing->sample->flags & IT_SAMPLE_16BIT ? 16 : 8;
+ size_rendered = size;
+
+ if (volume == 0) {
+ if (playing->declick_stage < 2) {
+ if (playing->sample->flags & IT_SAMPLE_STEREO)
+ size_rendered = dumb_resample_n_2_1(bits, &playing->resampler, NULL, size, 0, 0, delta);
+ else
+ size_rendered = dumb_resample_n_1_1(bits, &playing->resampler, NULL, size, 0, delta);
+ } else {
+ playing->declick_stage = 3;
+ }
+ } else {
+ lvol.volume = playing->ramp_volume [0];
+ rvol.volume = playing->ramp_volume [1];
+ lvol.delta = playing->ramp_delta [0] * main_delta;
+ rvol.delta = playing->ramp_delta [1] * main_delta;
+ lvol.target = playing->float_volume [0];
+ rvol.target = playing->float_volume [1];
+ rvol.mix = lvol.mix = volume;
+ if (ramp_style) {
+ if (playing->declick_stage == 1) {
+ size_rendered = render_playing_part(sigrenderer, playing, &lvol, &rvol, bits, delta, pos, size, samples, store_end_sample, 3);
+ } else if (playing->declick_stage == 0 || playing->declick_stage == 2) {
+ float declick_count = ((ramp_style == 2) ? 327.68 : 49.152) / main_delta; /* 5ms / 0.75ms */
+ float declick_remain = playing->declick_volume * declick_count;
+ float declick_dir = -1;
+ float declick_target;
+ int remain;
+ DUMB_VOLUME_RAMP_INFO declick_lvol, declick_rvol;
+ if (playing->declick_stage == 0) {
+ declick_remain = declick_count - declick_remain;
+ declick_dir = 1;
+ }
+ if (size < declick_remain) declick_remain = size;
+ remain = declick_remain;
+ declick_target = playing->declick_volume + declick_dir / declick_count * declick_remain;
+ declick_lvol.volume = lvol.volume * playing->declick_volume;
+ declick_rvol.volume = rvol.volume * playing->declick_volume;
+ lvol.volume += lvol.delta * declick_remain;
+ rvol.volume += rvol.delta * declick_remain;
+ declick_lvol.target = lvol.volume * declick_target;
+ declick_rvol.target = rvol.volume * declick_target;
+ declick_lvol.delta = (declick_lvol.target - declick_lvol.volume) / declick_remain;
+ declick_rvol.delta = (declick_rvol.target - declick_rvol.volume) / declick_remain;
+ declick_lvol.mix = declick_rvol.mix = volume;
+ if (remain < size) {
+ size_rendered = render_playing_part(sigrenderer, playing, &declick_lvol, &declick_rvol, bits, delta, pos, remain, samples, 0, 1);
+ if (size_rendered == remain) {
+ if (playing->declick_stage == 0) {
+ size_rendered += render_playing_part(sigrenderer, playing, &lvol, &rvol, bits, delta, pos + remain, size - remain, samples, store_end_sample, 2);
+ } else {
+ size_rendered = size;
+ }
+ }
+ playing->declick_stage++;
+ playing->declick_volume = 1;
+ } else {
+ size_rendered = render_playing_part(sigrenderer, playing, &declick_lvol, &declick_rvol, bits, delta, pos, remain, samples, store_end_sample, 3);
+ playing->declick_volume = declick_target;
+ }
+ } else /*if (playing->declick_stage == 3)*/ {
+ (*left_to_mix)++;
+ }
+ } else if (playing->declick_stage < 2) {
+ size_rendered = render_playing_part(sigrenderer, playing, &lvol, &rvol, bits, delta, pos, size, samples, store_end_sample, 3);
+ } else {
+ playing->declick_stage = 3;
+ (*left_to_mix)++;
+ }
+ playing->ramp_volume [0] = lvol.volume;
+ playing->ramp_volume [1] = rvol.volume;
+ (*left_to_mix)--;
+ }
+
+ if (playing->resampler.dir == 0)
+ playing->flags |= IT_PLAYING_DEAD;
+
+ return size_rendered;
+}
+#else
+static long render_playing_ramp(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float volume, float main_delta, float delta, long pos, long size, sample_t **samples, int store_end_sample, int *left_to_mix, int ramp_style)
+{
+ long rv, trv;
+ int l_t_m_temp, cr_which;
+ if (!size) return 0;
+
+ rv = 0;
+ cr_which = 3;
+
+ {
+ int quality = sigrenderer->resampling_quality;
+ if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality)
+ quality = playing->sample->max_resampling_quality;
+ playing->resampler.quality = quality;
+ }
+
+ if (ramp_style)
+ {
+ if (playing->declick_stage == 0) {
+ /* ramp up! */
+ cr_which = 1;
+ while (playing->declick_stage == 0 && size) {
+ l_t_m_temp = *left_to_mix;
+ if (size == 1) cr_which |= 2;
+ trv = render_playing(sigrenderer, playing, volume * playing->declick_volume, main_delta, delta, pos, 1, samples, store_end_sample, &l_t_m_temp, cr_which);
+ cr_which &= 2;
+ if (ramp_style == 2) playing->declick_volume += (1.f / 256.f) * main_delta;
+ else playing->declick_volume *= (float)pow(2.0f, main_delta);
+ if (playing->declick_volume >= 1.0f) {
+ playing->declick_volume = 1.0f;
+ playing->declick_stage = 1;
+ }
+ if (!trv) {
+ *left_to_mix = l_t_m_temp;
+ return rv;
+ }
+ rv += trv;
+ pos += trv;
+ size -= trv;
+ }
+
+ if (!size) {
+ *left_to_mix = l_t_m_temp;
+ return rv;
+ }
+
+ cr_which = 2;
+
+ }
+#ifdef RAMP_DOWN
+ else if (playing->declick_stage == 2) {
+ float halflife = pow(0.5, 1.0 / 64.0 * main_delta);
+ cr_which = 1;
+ while (playing->declick_stage == 2 && size) {
+ l_t_m_temp = *left_to_mix;
+ if (size == 1) cr_which |= 2;
+ trv = render_playing(sigrenderer, playing, volume * playing->declick_volume, main_delta, delta, pos, 1, samples, store_end_sample, &l_t_m_temp, cr_which);
+ cr_which &= 2;
+ /*if (ramp_style == 2) playing->declick_volume -= (1.f / 256.f) * main_delta;
+ else playing->declick_volume *= (float)pow(0.5f, main_delta);*/
+ playing->declick_volume *= halflife;
+ if (playing->declick_volume < (1.f / 256.f)) {
+ playing->declick_stage = 3;
+ }
+ if (!trv) {
+ *left_to_mix = l_t_m_temp;
+ return rv;
+ }
+ rv += trv;
+ pos += trv;
+ size -= trv;
+ }
+
+ if (size) rv += render_playing(sigrenderer, playing, volume * playing->declick_volume, main_delta, delta, pos, 1, samples, store_end_sample, left_to_mix, 2);
+ else *left_to_mix = l_t_m_temp;
+
+ return rv;
+
+ } else if (playing->declick_stage == 3) {
+ return size;
+ }
+#endif
+ } else if (playing->declick_stage >= 2) {
+ playing->declick_stage = 3;
+ return size;
+ }
+
+ return rv + render_playing(sigrenderer, playing, volume, main_delta, delta, pos, size, samples, store_end_sample, left_to_mix, cr_which);
+}
+#endif
+#else
+#define render_playing_ramp(sigrenderer, playing, volume, main_delta, delta, pos, size, samples, store_end_sample, left_to_mix, ramp_style) render_playing(sigrenderer, playing, volume, main_delta, delta, pos, size, samples, store_end_sample, left_to_mix, 3)
+#endif
+
+typedef struct IT_TO_MIX
+{
+ IT_PLAYING *playing;
+ float volume;
+}
+IT_TO_MIX;
+
+
+
+static int it_to_mix_compare(const void *e1, const void *e2)
+{
+ if (((const IT_TO_MIX *)e1)->volume > ((const IT_TO_MIX *)e2)->volume)
+ return -1;
+
+ if (((const IT_TO_MIX *)e1)->volume < ((const IT_TO_MIX *)e2)->volume)
+ return 1;
+
+ return 0;
+}
+
+
+
+static void apply_pitch_modifications(DUMB_IT_SIGDATA *sigdata, IT_PLAYING *playing, float *delta, int *cutoff)
+{
+ {
+ int sample_vibrato_shift;
+ switch (playing->sample_vibrato_waveform)
+ {
+ default:
+ sample_vibrato_shift = it_sine[playing->sample_vibrato_time];
+ break;
+ case 1:
+ sample_vibrato_shift = it_sawtooth[playing->sample_vibrato_time];
+ break;
+ case 2:
+ sample_vibrato_shift = it_squarewave[playing->sample_vibrato_time];
+ break;
+ case 3:
+ sample_vibrato_shift = (rand() % 129) - 64;
+ break;
+ case 4:
+ sample_vibrato_shift = it_xm_squarewave[playing->sample_vibrato_time];
+ break;
+ case 5:
+ sample_vibrato_shift = it_xm_ramp[playing->sample_vibrato_time];
+ break;
+ case 6:
+ sample_vibrato_shift = it_xm_ramp[255-playing->sample_vibrato_time];
+ break;
+ }
+
+ if (sigdata->flags & IT_WAS_AN_XM) {
+ int depth = playing->sample->vibrato_depth; /* True depth */
+ if (playing->sample->vibrato_rate) {
+ depth *= playing->sample_vibrato_depth; /* Tick number */
+ depth /= playing->sample->vibrato_rate; /* XM sweep */
+ }
+ sample_vibrato_shift *= depth;
+ } else
+ sample_vibrato_shift *= playing->sample_vibrato_depth >> 8;
+
+ sample_vibrato_shift >>= 4;
+
+ if (sample_vibrato_shift) {
+ if ((sigdata->flags & IT_LINEAR_SLIDES) || !(sigdata->flags & IT_WAS_AN_XM))
+ *delta *= (float)pow(DUMB_PITCH_BASE, sample_vibrato_shift);
+ else {
+ /* complicated! */
+ float scale = *delta / playing->delta;
+
+ *delta = (1.0f / 65536.0f) / playing->delta;
+
+ *delta -= sample_vibrato_shift / AMIGA_DIVISOR;
+
+ if (*delta < (1.0f / 65536.0f) / 32767.0f) {
+ *delta = (1.0f / 65536.0f) / 32767.0f;
+ }
+
+ *delta = (1.0f / 65536.0f) / *delta * scale;
+ }
+ }
+ }
+
+ if (playing->env_instrument &&
+ (playing->enabled_envelopes & IT_ENV_PITCH))
+ {
+ int p = envelope_get_y(&playing->env_instrument->pitch_envelope, &playing->pitch_envelope);
+ if (playing->env_instrument->pitch_envelope.flags & IT_ENVELOPE_PITCH_IS_FILTER)
+ *cutoff = (*cutoff * (p+(32<<IT_ENVELOPE_SHIFT))) >> (6 + IT_ENVELOPE_SHIFT);
+ else
+ *delta *= (float)pow(DUMB_PITCH_BASE, p >> (IT_ENVELOPE_SHIFT - 7));
+ }
+}
+
+
+
+static void render(DUMB_IT_SIGRENDERER *sigrenderer, float volume, float delta, long pos, long size, sample_t **samples)
+{
+ int i;
+
+ int n_to_mix = 0;
+ IT_TO_MIX to_mix[DUMB_IT_TOTAL_CHANNELS];
+ int left_to_mix = dumb_it_max_to_mix;
+
+ sample_t **samples_to_filter = NULL;
+
+ int ramp_style = sigrenderer->ramp_style;
+
+ //int max_output = sigrenderer->max_output;
+
+ if (ramp_style > 2) {
+ if ((sigrenderer->sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_MOD)) == IT_WAS_AN_XM) ramp_style = 2;
+ else ramp_style -= 3;
+ }
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ if (sigrenderer->channel[i].playing && !(sigrenderer->channel[i].playing->flags & IT_PLAYING_DEAD)) {
+ to_mix[n_to_mix].playing = sigrenderer->channel[i].playing;
+ to_mix[n_to_mix].volume = volume == 0 ? 0 : calculate_volume(sigrenderer, sigrenderer->channel[i].playing, volume);
+ n_to_mix++;
+ }
+ }
+
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
+ if (sigrenderer->playing[i]) { /* Won't be dead; it would have been freed. */
+ to_mix[n_to_mix].playing = sigrenderer->playing[i];
+ to_mix[n_to_mix].volume = volume == 0 ? 0 : calculate_volume(sigrenderer, sigrenderer->playing[i], volume);
+ n_to_mix++;
+ }
+ }
+
+ if (volume != 0)
+ qsort(to_mix, n_to_mix, sizeof(IT_TO_MIX), &it_to_mix_compare);
+
+ for (i = 0; i < n_to_mix; i++) {
+ IT_PLAYING *playing = to_mix[i].playing;
+ float note_delta = delta * playing->delta;
+ int cutoff = playing->filter_cutoff << IT_ENVELOPE_SHIFT;
+ //int output = min( playing->output, max_output );
+
+ apply_pitch_modifications(sigrenderer->sigdata, playing, &note_delta, &cutoff);
+
+ if (cutoff != 127 << IT_ENVELOPE_SHIFT || playing->filter_resonance != 0) {
+ playing->true_filter_cutoff = cutoff;
+ playing->true_filter_resonance = playing->filter_resonance;
+ }
+
+ if (volume && (playing->true_filter_cutoff != 127 << IT_ENVELOPE_SHIFT || playing->true_filter_resonance != 0)) {
+ if (!samples_to_filter) {
+ samples_to_filter = allocate_sample_buffer(sigrenderer->n_channels, size + 1);
+ if (!samples_to_filter) {
+ render_playing_ramp(sigrenderer, playing, 0, delta, note_delta, pos, size, NULL, 0, &left_to_mix, ramp_style);
+ continue;
+ }
+ }
+ {
+ long size_rendered;
+ DUMB_CLICK_REMOVER **cr = sigrenderer->click_remover;
+ dumb_silence(samples_to_filter[0], sigrenderer->n_channels * (size + 1));
+ sigrenderer->click_remover = NULL;
+ size_rendered = render_playing_ramp(sigrenderer, playing, volume, delta, note_delta, 0, size, samples_to_filter, 1, &left_to_mix, ramp_style);
+ sigrenderer->click_remover = cr;
+ if (sigrenderer->n_channels == 2) {
+ it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[0 /*output*/], pos, samples_to_filter[0], size_rendered,
+ 2, (int)(65536.0f/delta), playing->true_filter_cutoff, playing->true_filter_resonance);
+ it_filter(cr ? cr[1] : NULL, &playing->filter_state[1], samples[0 /*output*/]+1, pos, samples_to_filter[0]+1, size_rendered,
+ 2, (int)(65536.0f/delta), playing->true_filter_cutoff, playing->true_filter_resonance);
+ } else {
+ it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[0 /*output*/], pos, samples_to_filter[0], size_rendered,
+ 1, (int)(65536.0f/delta), playing->true_filter_cutoff, playing->true_filter_resonance);
+ }
+ // FIXME: filtering is not prevented by low left_to_mix!
+ // FIXME: change 'warning' to 'FIXME' everywhere
+ }
+ } else {
+ it_reset_filter_state(&playing->filter_state[0]);
+ it_reset_filter_state(&playing->filter_state[1]);
+ render_playing_ramp(sigrenderer, playing, volume, delta, note_delta, pos, size, samples /*&samples[output]*/, 0, &left_to_mix, ramp_style);
+ }
+ }
+
+ destroy_sample_buffer(samples_to_filter);
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ if (sigrenderer->channel[i].playing) {
+ //if ((sigrenderer->channel[i].playing->flags & (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) == (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) {
+ // This change was made so Gxx would work correctly when a note faded out or whatever. Let's hope nothing else was broken by it.
+ if (
+#ifdef RAMP_DOWN
+ (sigrenderer->channel[i].playing->declick_stage == 3) ||
+#endif
+ (sigrenderer->channel[i].playing->flags & IT_PLAYING_DEAD)) {
+ free(sigrenderer->channel[i].playing);
+ sigrenderer->channel[i].playing = NULL;
+ }
+ }
+ }
+
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
+ if (sigrenderer->playing[i]) {
+ if (
+#ifdef RAMP_DOWN
+ (sigrenderer->playing[i]->declick_stage == 3) ||
+#endif
+ (sigrenderer->playing[i]->flags & IT_PLAYING_DEAD)) {
+ free(sigrenderer->playing[i]);
+ sigrenderer->playing[i] = NULL;
+ }
+ }
+ }
+}
+
+
+
+static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_channels, int startorder, IT_CALLBACKS *callbacks, DUMB_CLICK_REMOVER **cr)
+{
+ DUMB_IT_SIGRENDERER *sigrenderer;
+ int i;
+
+ if (startorder > sigdata->n_orders) {
+ free(callbacks);
+ dumb_destroy_click_remover_array(n_channels, cr);
+ return NULL;
+ }
+
+ sigrenderer = malloc(sizeof(*sigrenderer));
+ if (!sigrenderer) {
+ free(callbacks);
+ dumb_destroy_click_remover_array(n_channels, cr);
+ return NULL;
+ }
+
+ sigrenderer->callbacks = callbacks;
+ sigrenderer->click_remover = cr;
+
+ sigrenderer->sigdata = sigdata;
+ sigrenderer->n_channels = n_channels;
+ sigrenderer->resampling_quality = dumb_resampling_quality;
+ sigrenderer->ramp_style = 0;
+ sigrenderer->globalvolume = sigdata->global_volume;
+ sigrenderer->tempo = sigdata->tempo;
+
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ IT_CHANNEL *channel = &sigrenderer->channel[i];
+#if IT_CHANNEL_MUTED != 1
+#error this is wrong
+#endif
+ channel->flags = sigdata->channel_pan[i] >> 7;
+ channel->volume = (sigdata->flags & IT_WAS_AN_XM) ? 0 : 64;
+ channel->pan = sigdata->channel_pan[i] & 0x7F;
+ channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
+ channel->channelvolume = sigdata->channel_volume[i];
+ channel->instrument = 0;
+ channel->sample = 0;
+ channel->note = 0;
+ channel->SFmacro = 0;
+ channel->filter_cutoff = 127;
+ channel->filter_resonance = 0;
+ channel->new_note_action = 0xFF;
+ channel->xm_retrig = 0;
+ channel->retrig_tick = 0;
+ channel->tremor_time = 0;
+ channel->vibrato_waveform = 0;
+ channel->tremolo_waveform = 0;
+ channel->panbrello_waveform = 0;
+ channel->glissando = 0;
+ channel->toneslide = 0;
+ channel->ptm_toneslide = 0;
+ channel->ptm_last_toneslide = 0;
+ channel->midi_state = 0;
+ channel->lastvolslide = 0;
+ channel->lastDKL = 0;
+ channel->lastEF = 0;
+ channel->lastG = 0;
+ channel->lastHspeed = 0;
+ channel->lastHdepth = 0;
+ channel->lastRspeed = 0;
+ channel->lastRdepth = 0;
+ channel->lastYspeed = 0;
+ channel->lastYdepth = 0;
+ channel->lastI = 0;
+ channel->lastJ = 0;
+ channel->lastN = 0;
+ channel->lastO = 0;
+ channel->high_offset = 0;
+ channel->lastP = 0;
+ channel->lastQ = 0;
+ channel->lastS = 0;
+ channel->pat_loop_row = 0;
+ channel->pat_loop_count = 0;
+ channel->pat_loop_end_row = 0;
+ channel->lastW = 0;
+ channel->xm_lastE1 = 0;
+ channel->xm_lastE2 = 0;
+ channel->xm_lastEA = 0;
+ channel->xm_lastEB = 0;
+ channel->xm_lastX1 = 0;
+ channel->xm_lastX2 = 0;
+ channel->playing = NULL;
+#ifdef BIT_ARRAY_BULLSHIT
+ channel->played_patjump = NULL;
+ channel->played_patjump_order = 0xFFFE;
+#endif
+ //channel->output = 0;
+ }
+
+ if (sigdata->flags & IT_WAS_A_669)
+ reset_effects(sigrenderer);
+
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++)
+ sigrenderer->playing[i] = NULL;
+
+ sigrenderer->speed = sigdata->speed;
+
+ sigrenderer->processrow = 0xFFFE;
+ sigrenderer->n_rows = 0;
+ sigrenderer->breakrow = 0;
+ sigrenderer->rowcount = 1;
+ sigrenderer->order = startorder;
+ /* meh!
+ if (startorder > 0) {
+ int n;
+ for (n = startorder - 1; n >= 0; n--) {
+ if (sigdata->order[n] > sigdata->n_patterns) {
+ sigrenderer->restart_position = n + 1;
+ break;
+ }
+ }
+ }
+ */
+ if (startorder > 0) {
+ sigrenderer->restart_position = startorder;
+ } else {
+ sigrenderer->restart_position = sigdata->restart_position;
+ }
+
+ sigrenderer->row = 0;
+ sigrenderer->processorder = startorder - 1;
+ sigrenderer->tick = 1;
+
+ {
+ int order;
+ for (order = 0; order < sigdata->n_orders; order++) {
+ int n = sigdata->order[order];
+ if (n < sigdata->n_patterns) goto found_valid_order;
+#ifdef INVALID_ORDERS_END_SONG
+ if (n != IT_ORDER_SKIP)
+#else
+ if (n == IT_ORDER_END)
+#endif
+ break;
+ }
+ /* If we get here, there were no valid orders in the song. */
+ _dumb_it_end_sigrenderer(sigrenderer);
+ return NULL;
+ }
+ found_valid_order:
+
+ sigrenderer->time_left = 0;
+ sigrenderer->sub_time_left = 0;
+
+#ifdef BIT_ARRAY_BULLSHIT
+ sigrenderer->played = bit_array_create(sigdata->n_orders * 256);
+#endif
+
+ sigrenderer->gvz_time = 0;
+ sigrenderer->gvz_sub_time = 0;
+
+ //sigrenderer->max_output = 0;
+
+ return sigrenderer;
+}
+
+
+void dumb_it_set_resampling_quality(DUMB_IT_SIGRENDERER * sigrenderer, int quality)
+{
+ if (sigrenderer && quality >= 0 && quality < DUMB_RQ_N_LEVELS)
+ {
+ int i;
+ sigrenderer->resampling_quality = quality;
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ if (sigrenderer->channel[i].playing)
+ {
+ IT_PLAYING * playing = sigrenderer->channel[i].playing;
+ playing->resampling_quality = quality;
+ playing->resampler.quality = quality;
+ }
+ }
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) {
+ if (sigrenderer->playing[i]) {
+ IT_PLAYING * playing = sigrenderer->playing[i];
+ playing->resampling_quality = quality;
+ playing->resampler.quality = quality;
+ }
+ }
+ }
+}
+
+
+void dumb_it_set_ramp_style(DUMB_IT_SIGRENDERER * sigrenderer, int ramp_style) {
+ if (sigrenderer && ramp_style >= 0 && ramp_style <= 4) {
+ sigrenderer->ramp_style = ramp_style;
+ }
+}
+
+
+void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data)
+{
+ if (sigrenderer) {
+ sigrenderer->callbacks->loop = callback;
+ sigrenderer->callbacks->loop_data = data;
+ }
+}
+
+
+
+void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data)
+{
+ if (sigrenderer) {
+ sigrenderer->callbacks->xm_speed_zero = callback;
+ sigrenderer->callbacks->xm_speed_zero_data = data;
+ }
+}
+
+
+
+void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data, int channel, unsigned char midi_byte), void *data)
+{
+ if (sigrenderer) {
+ sigrenderer->callbacks->midi = callback;
+ sigrenderer->callbacks->midi_data = data;
+ }
+}
+
+
+
+void dumb_it_set_global_volume_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data)
+{
+ if (sigrenderer) {
+ sigrenderer->callbacks->global_volume_zero = callback;
+ sigrenderer->callbacks->global_volume_zero_data = data;
+ }
+}
+
+
+
+static IT_CALLBACKS *create_callbacks(void)
+{
+ IT_CALLBACKS *callbacks = malloc(sizeof(*callbacks));
+ if (!callbacks) return NULL;
+ callbacks->loop = NULL;
+ callbacks->xm_speed_zero = NULL;
+ callbacks->midi = NULL;
+ callbacks->global_volume_zero = NULL;
+ return callbacks;
+}
+
+
+
+static DUMB_IT_SIGRENDERER *dumb_it_init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_channels, int startorder)
+{
+ IT_CALLBACKS *callbacks;
+
+ if (!sigdata) return NULL;
+
+ callbacks = create_callbacks();
+ if (!callbacks) return NULL;
+
+ return init_sigrenderer(sigdata, n_channels, startorder, callbacks,
+ dumb_create_click_remover_array(n_channels));
+}
+
+
+
+DUH_SIGRENDERER *dumb_it_start_at_order(DUH *duh, int n_channels, int startorder)
+{
+ DUMB_IT_SIGDATA *itsd = duh_get_it_sigdata(duh);
+ DUMB_IT_SIGRENDERER *itsr = dumb_it_init_sigrenderer(itsd, n_channels, startorder);
+ /*duh->length = dumb_it_build_checkpoints(itsd, startorder);*/
+ return duh_encapsulate_it_sigrenderer(itsr, n_channels, 0);
+}
+
+
+
+static sigrenderer_t *it_start_sigrenderer(DUH *duh, sigdata_t *vsigdata, int n_channels, long pos)
+{
+ DUMB_IT_SIGDATA *sigdata = vsigdata;
+ DUMB_IT_SIGRENDERER *sigrenderer;
+
+ (void)duh;
+
+ {
+ IT_CALLBACKS *callbacks = create_callbacks();
+ if (!callbacks) return NULL;
+
+ if (sigdata->checkpoint) {
+ IT_CHECKPOINT *checkpoint = sigdata->checkpoint;
+ while (checkpoint->next && checkpoint->next->time < pos)
+ checkpoint = checkpoint->next;
+ sigrenderer = dup_sigrenderer(checkpoint->sigrenderer, n_channels, callbacks);
+ if (!sigrenderer) return NULL;
+ sigrenderer->click_remover = dumb_create_click_remover_array(n_channels);
+ pos -= checkpoint->time;
+ } else {
+ sigrenderer = init_sigrenderer(sigdata, n_channels, 0, callbacks,
+ dumb_create_click_remover_array(n_channels));
+ if (!sigrenderer) return NULL;
+ }
+ }
+
+ while (pos >= sigrenderer->time_left) {
+ render(sigrenderer, 0, 1.0f, 0, sigrenderer->time_left, NULL);
+
+ pos -= sigrenderer->time_left;
+ sigrenderer->time_left = 0;
+
+ if (process_tick(sigrenderer)) {
+ _dumb_it_end_sigrenderer(sigrenderer);
+ return NULL;
+ }
+ }
+
+ render(sigrenderer, 0, 1.0f, 0, pos, NULL);
+ sigrenderer->time_left -= pos;
+
+ return sigrenderer;
+}
+
+
+
+static long it_sigrenderer_get_samples(
+ sigrenderer_t *vsigrenderer,
+ float volume, float delta,
+ long size, sample_t **samples
+)
+{
+ DUMB_IT_SIGRENDERER *sigrenderer = vsigrenderer;
+ long pos;
+ int dt;
+ long todo;
+ LONG_LONG t;
+
+ if (sigrenderer->order < 0) return 0; // problematic
+
+ pos = 0;
+ dt = (int)(delta * 65536.0f + 0.5f);
+
+ /* When samples is finally used in render_playing(), it won't be used if
+ * volume is 0.
+ */
+ if (!samples) volume = 0;
+
+ for (;;) {
+ todo = (long)((((LONG_LONG)sigrenderer->time_left << 16) | sigrenderer->sub_time_left) / dt);
+
+ if (todo >= size)
+ break;
+
+ render(sigrenderer, volume, delta, pos, todo, samples);
+
+ pos += todo;
+ size -= todo;
+
+ t = sigrenderer->sub_time_left - (LONG_LONG)todo * dt;
+ sigrenderer->sub_time_left = (long)t & 65535;
+ sigrenderer->time_left += (long)(t >> 16);
+
+ if (process_tick(sigrenderer)) {
+ sigrenderer->order = -1;
+ sigrenderer->row = -1;
+ return pos;
+ }
+ }
+
+ render(sigrenderer, volume, delta, pos, size, samples);
+
+ pos += size;
+
+ t = sigrenderer->sub_time_left - (LONG_LONG)size * dt;
+ sigrenderer->sub_time_left = (long)t & 65535;
+ sigrenderer->time_left += (long)(t >> 16);
+
+ if (samples)
+ dumb_remove_clicks_array(sigrenderer->n_channels, sigrenderer->click_remover, samples, pos, 512.0f / delta);
+
+ return pos;
+}
+
+
+
+static void it_sigrenderer_get_current_sample(sigrenderer_t *vsigrenderer, float volume, sample_t *samples)
+{
+ DUMB_IT_SIGRENDERER *sigrenderer = vsigrenderer;
+ (void)volume; // for consideration: in any of these such functions, is 'volume' going to be required?
+ dumb_click_remover_get_offset_array(sigrenderer->n_channels, sigrenderer->click_remover, samples);
+}
+
+
+
+void _dumb_it_end_sigrenderer(sigrenderer_t *vsigrenderer)
+{
+ DUMB_IT_SIGRENDERER *sigrenderer = vsigrenderer;
+
+ int i;
+
+ if (sigrenderer) {
+ for (i = 0; i < DUMB_IT_N_CHANNELS; i++) {
+ if (sigrenderer->channel[i].playing)
+ free(sigrenderer->channel[i].playing);
+#ifdef BIT_ARRAY_BULLSHIT
+ bit_array_destroy(sigrenderer->channel[i].played_patjump);
+#endif
+ }
+
+ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++)
+ if (sigrenderer->playing[i])
+ free(sigrenderer->playing[i]);
+
+ dumb_destroy_click_remover_array(sigrenderer->n_channels, sigrenderer->click_remover);
+
+ if (sigrenderer->callbacks)
+ free(sigrenderer->callbacks);
+
+#ifdef BIT_ARRAY_BULLSHIT
+ bit_array_destroy(sigrenderer->played);
+#endif
+
+ free(vsigrenderer);
+ }
+}
+
+
+
+DUH_SIGTYPE_DESC _dumb_sigtype_it = {
+ SIGTYPE_IT,
+ NULL,
+ &it_start_sigrenderer,
+ NULL,
+ &it_sigrenderer_get_samples,
+ &it_sigrenderer_get_current_sample,
+ &_dumb_it_end_sigrenderer,
+ &_dumb_it_unload_sigdata
+};
+
+
+
+DUH_SIGRENDERER *duh_encapsulate_it_sigrenderer(DUMB_IT_SIGRENDERER *it_sigrenderer, int n_channels, long pos)
+{
+ return duh_encapsulate_raw_sigrenderer(it_sigrenderer, &_dumb_sigtype_it, n_channels, pos);
+}
+
+
+
+DUMB_IT_SIGRENDERER *duh_get_it_sigrenderer(DUH_SIGRENDERER *sigrenderer)
+{
+ return duh_get_raw_sigrenderer(sigrenderer, SIGTYPE_IT);
+}
+
+
+
+/* Values of 64 or more will access NNA channels here. */
+void dumb_it_sr_get_channel_state(DUMB_IT_SIGRENDERER *sr, int channel, DUMB_IT_CHANNEL_STATE *state)
+{
+ IT_PLAYING *playing;
+ int t; /* temporary var for holding accurate pan and filter cutoff */
+ float delta;
+ ASSERT(channel < DUMB_IT_TOTAL_CHANNELS);
+ if (!sr) { state->sample = 0; return; }
+ if (channel >= DUMB_IT_N_CHANNELS) {
+ playing = sr->playing[channel - DUMB_IT_N_CHANNELS];
+ if (!playing) { state->sample = 0; return; }
+ } else {
+ playing = sr->channel[channel].playing;
+ if (!playing) { state->sample = 0; return; }
+ }
+
+ if (playing->flags & IT_PLAYING_DEAD) { state->sample = 0; return; }
+
+ state->channel = playing->channel - sr->channel;
+ state->sample = playing->sampnum;
+ state->volume = calculate_volume(sr, playing, 1.0f);
+
+ t = apply_pan_envelope(playing);
+ state->pan = (unsigned char)((t + 128) >> IT_ENVELOPE_SHIFT);
+ state->subpan = (signed char)t;
+
+ delta = playing->delta * 65536.0f;
+ t = playing->filter_cutoff << IT_ENVELOPE_SHIFT;
+ apply_pitch_modifications(sr->sigdata, playing, &delta, &t);
+ state->freq = (int)delta;
+ if (t == 127 << IT_ENVELOPE_SHIFT && playing->filter_resonance == 0) {
+ state->filter_resonance = playing->true_filter_resonance;
+ t = playing->true_filter_cutoff;
+ } else
+ state->filter_resonance = playing->filter_resonance;
+ state->filter_cutoff = (unsigned char)(t >> 8);
+ state->filter_subcutoff = (unsigned char)t;
+}
+
+
+
+int dumb_it_callback_terminate(void *data)
+{
+ (void)data;
+ return 1;
+}
+
+
+
+int dumb_it_callback_midi_block(void *data, int channel, unsigned char midi_byte)
+{
+ (void)data;
+ (void)channel;
+ (void)midi_byte;
+ return 1;
+}
+
+
+
+#define IT_CHECKPOINT_INTERVAL (30 * 65536) /* Half a minute */
+
+#define FUCKIT_THRESHOLD (120 * 60 * 65536) /* two hours? probably a pattern loop mess... */
+
+/* Returns the length of the module, up until it first loops. */
+long dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata, int startorder)
+{
+ IT_CHECKPOINT *checkpoint;
+ if (!sigdata) return 0;
+ checkpoint = sigdata->checkpoint;
+ while (checkpoint) {
+ IT_CHECKPOINT *next = checkpoint->next;
+ _dumb_it_end_sigrenderer(checkpoint->sigrenderer);
+ free(checkpoint);
+ checkpoint = next;
+ }
+ sigdata->checkpoint = NULL;
+ checkpoint = malloc(sizeof(*checkpoint));
+ if (!checkpoint) return 0;
+ checkpoint->time = 0;
+ checkpoint->sigrenderer = dumb_it_init_sigrenderer(sigdata, 0, startorder);
+ if (!checkpoint->sigrenderer) {
+ free(checkpoint);
+ return 0;
+ }
+ checkpoint->sigrenderer->callbacks->loop = &dumb_it_callback_terminate;
+ checkpoint->sigrenderer->callbacks->xm_speed_zero = &dumb_it_callback_terminate;
+ checkpoint->sigrenderer->callbacks->global_volume_zero = &dumb_it_callback_terminate;
+
+ if (sigdata->checkpoint)
+ {
+ IT_CHECKPOINT *checkpoint = sigdata->checkpoint;
+ while (checkpoint) {
+ IT_CHECKPOINT *next = checkpoint->next;
+ _dumb_it_end_sigrenderer(checkpoint->sigrenderer);
+ free(checkpoint);
+ checkpoint = next;
+ }
+ }
+
+ sigdata->checkpoint = checkpoint;
+
+ for (;;) {
+ long l;
+ DUMB_IT_SIGRENDERER *sigrenderer = dup_sigrenderer(checkpoint->sigrenderer, 0, checkpoint->sigrenderer->callbacks);
+ checkpoint->sigrenderer->callbacks = NULL;
+ if (!sigrenderer) {
+ checkpoint->next = NULL;
+ return checkpoint->time;
+ }
+
+ l = it_sigrenderer_get_samples(sigrenderer, 0, 1.0f, IT_CHECKPOINT_INTERVAL, NULL);
+ if (l < IT_CHECKPOINT_INTERVAL) {
+ _dumb_it_end_sigrenderer(sigrenderer);
+ checkpoint->next = NULL;
+ return checkpoint->time + l;
+ }
+
+ checkpoint->next = malloc(sizeof(*checkpoint->next));
+ if (!checkpoint->next) {
+ _dumb_it_end_sigrenderer(sigrenderer);
+ return checkpoint->time + IT_CHECKPOINT_INTERVAL;
+ }
+
+ checkpoint->next->time = checkpoint->time + IT_CHECKPOINT_INTERVAL;
+ checkpoint = checkpoint->next;
+ checkpoint->sigrenderer = sigrenderer;
+
+ if (checkpoint->time >= FUCKIT_THRESHOLD) {
+ checkpoint->next = NULL;
+ return 0;
+ }
+ }
+}
+
+
+
+void dumb_it_do_initial_runthrough(DUH *duh)
+{
+ if (duh) {
+ DUMB_IT_SIGDATA *sigdata = duh_get_it_sigdata(duh);
+
+ if (sigdata)
+ duh_set_length(duh, dumb_it_build_checkpoints(sigdata, 0));
+ }
+}
+
+static int is_pattern_silent(IT_PATTERN * pattern, int order) {
+ int ret = 1;
+ IT_ENTRY * entry, * end;
+ if (!pattern || !pattern->n_rows || !pattern->n_entries || !pattern->entry) return 2;
+
+ if ( pattern->n_entries == pattern->n_rows ) {
+ int n;
+ entry = pattern->entry;
+ for ( n = 0; n < pattern->n_entries; ++n, ++entry ) {
+ if ( !IT_IS_END_ROW(entry) ) break;
+ }
+ if ( n == pattern->n_entries ) return 2;
+ // broken?
+ }
+
+ entry = pattern->entry;
+ end = entry + pattern->n_entries;
+
+ while (entry < end) {
+ if (!IT_IS_END_ROW(entry)) {
+ if (entry->mask & (IT_ENTRY_INSTRUMENT | IT_ENTRY_VOLPAN))
+ return 0;
+ if (entry->mask & IT_ENTRY_NOTE && entry->note < 120)
+ return 0;
+ if (entry->mask & IT_ENTRY_EFFECT) {
+ switch (entry->effect) {
+ case IT_SET_GLOBAL_VOLUME:
+ if (entry->effectvalue) return 0;
+ break;
+
+ case IT_SET_SPEED:
+ if (entry->effectvalue > 64) ret++;
+ break;
+
+ case IT_SET_SONG_TEMPO:
+ case IT_XM_KEY_OFF:
+ break;
+
+ case IT_JUMP_TO_ORDER:
+ if (entry->effectvalue != order)
+ return 0;
+ break;
+
+ case IT_S:
+ switch (entry->effectvalue >> 4) {
+ case 0: // meh bastard
+ if ( entry->effectvalue != 0 ) return 0;
+ break;
+
+ case IT_S_FINE_PATTERN_DELAY:
+ case IT_S_PATTERN_LOOP:
+ case IT_S_PATTERN_DELAY:
+ ret++;
+ break;
+
+ case IT_S7:
+ if ((entry->effectvalue & 15) > 2)
+ return 0;
+ break;
+
+ default:
+ return 0;
+ }
+ break;
+
+ // clever idiot with his S L O W crap; do nothing
+ case IT_VOLSLIDE_TONEPORTA:
+ case IT_SET_SAMPLE_OFFSET:
+ case IT_GLOBAL_VOLUME_SLIDE:
+ if ( entry->effectvalue != 0 ) return 0;
+ break;
+
+ // genius also uses this instead of jump to order by mistake, meh, and it's bloody BCD
+ case IT_BREAK_TO_ROW:
+ if ( ( ( entry->effectvalue >> 4 ) * 10 + ( entry->effectvalue & 15 ) ) != order ) return 0;
+ break;
+
+ default:
+ return 0;
+ }
+ }
+ }
+ entry++;
+ }
+
+ return ret;
+}
+
+int dumb_it_trim_silent_patterns(DUH * duh) {
+ int n;
+ DUMB_IT_SIGDATA *sigdata;
+
+ if (!duh) return -1;
+
+ sigdata = duh_get_it_sigdata(duh);
+
+ if (!sigdata || !sigdata->order || !sigdata->pattern) return -1;
+
+ for (n = 0; n < sigdata->n_orders; n++) {
+ int p = sigdata->order[n];
+ if (p < sigdata->n_patterns) {
+ IT_PATTERN * pattern = &sigdata->pattern[p];
+ if (is_pattern_silent(pattern, n) > 1) {
+ pattern->n_rows = 1;
+ pattern->n_entries = 0;
+ if (pattern->entry)
+ {
+ free(pattern->entry);
+ pattern->entry = NULL;
+ }
+ } else
+ break;
+ }
+ }
+
+ if (n == sigdata->n_orders) return -1;
+
+ for (n = sigdata->n_orders - 1; n >= 0; n--) {
+ int p = sigdata->order[n];
+ if (p < sigdata->n_patterns) {
+ IT_PATTERN * pattern = &sigdata->pattern[p];
+ if (is_pattern_silent(pattern, n) > 1) {
+ pattern->n_rows = 1;
+ pattern->n_entries = 0;
+ if (pattern->entry)
+ {
+ free(pattern->entry);
+ pattern->entry = NULL;
+ }
+ } else
+ break;
+ }
+ }
+
+ if (n < 0) return -1;
+
+ /*duh->length = dumb_it_build_checkpoints(sigdata, 0);*/
+
+ return 0;
+}
+
+int dumb_it_scan_for_playable_orders(DUMB_IT_SIGDATA *sigdata, dumb_scan_callback callback, void * callback_data)
+{
+ int n;
+ long length;
+ void * ba_played;
+ DUMB_IT_SIGRENDERER * sigrenderer;
+
+ if (!sigdata->n_orders || !sigdata->order) return -1;
+
+ ba_played = bit_array_create(sigdata->n_orders * 256);
+ if (!ba_played) return -1;
+
+ for (n = 0; n < sigdata->n_orders; n++) {
+ if ((sigdata->order[n] >= sigdata->n_patterns) ||
+ (is_pattern_silent(&sigdata->pattern[sigdata->order[n]], n) > 1))
+ bit_array_set(ba_played, n * 256);
+ }
+
+ for (;;) {
+ for (n = 0; n < sigdata->n_orders; n++) {
+ if (!bit_array_test_range(ba_played, n * 256, 256)) break;
+ }
+
+ if (n == sigdata->n_orders) break;
+
+ sigrenderer = dumb_it_init_sigrenderer(sigdata, 0, n);
+ if (!sigrenderer) {
+ bit_array_destroy(ba_played);
+ return -1;
+ }
+ sigrenderer->callbacks->loop = &dumb_it_callback_terminate;
+ sigrenderer->callbacks->xm_speed_zero = &dumb_it_callback_terminate;
+ sigrenderer->callbacks->global_volume_zero = &dumb_it_callback_terminate;
+
+ length = 0;
+
+ for (;;) {
+ long l;
+
+ l = it_sigrenderer_get_samples(sigrenderer, 0, 1.0f, IT_CHECKPOINT_INTERVAL, NULL);
+ length += l;
+ if (l < IT_CHECKPOINT_INTERVAL || length >= FUCKIT_THRESHOLD) {
+ /* SONG OVA! */
+ break;
+ }
+ }
+
+ if ((*callback)(callback_data, n, length) < 0) return -1;
+
+ bit_array_merge(ba_played, sigrenderer->played, 0);
+
+ _dumb_it_end_sigrenderer(sigrenderer);
+ }
+
+ bit_array_destroy(ba_played);
+
+ return 0;
+}