/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque * / \ * / . \ * itrender.c - Code to render an Impulse Tracker / / \ \ * module. | < / \_ * | \/ /\ / * Written - painstakingly - by entheh. \_ / > / * | \ / / * | ' / * \__/ */ #include #include #include "dumb.h" #include "internal/it.h" 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; 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; dst->channel_volume = src->channel_volume; dst->volume = src->volume; dst->pan = src->pan; dst->note = src->note; 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->tremolo_speed = src->tremolo_speed; dst->tremolo_depth = src->tremolo_depth; dst->tremolo_time = src->tremolo_time; dst->sample_vibrato_time = src->sample_vibrato_time; dst->sample_vibrato_depth = src->sample_vibrato_depth; dst->slide = src->slide; dst->delta = src->delta; 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; 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->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->portamento = src->portamento; dst->toneporta = src->toneporta; dst->destnote = src->destnote; 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->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); } /* 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->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->pat_loop_row = src->pat_loop_row; 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; return dst; } static 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; } #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< 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 static 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 0 /** 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 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 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 }; #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_effects(DUMB_IT_SIGRENDERER *sigrenderer) { int i; sigrenderer->globalvolslide = 0; sigrenderer->temposlide = 0; for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { IT_CHANNEL *channel = &sigrenderer->channel[i]; 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->playing) { channel->playing->vibrato_n = 0; channel->playing->tremolo_speed = 0; channel->playing->tremolo_depth = 0; } } } 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->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->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 channels = playing->sample->flags & IT_SAMPLE_STEREO ? 2 : 1; dumb_reset_resampler_n(bits, &playing->resampler, playing->sample->data, channels, pos, 0, 0); playing->resampler.pickup_data = playing; playing->time_lost = 0; playing->flags &= ~IT_PLAYING_DEAD; it_playing_update_resamplers(playing); } static void update_retrig(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); 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); 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; } } } 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 && !IT_IS_SURROUND(channel->pan)) { if (sigrenderer->sigdata->flags & IT_WAS_AN_XM) { if (channel->panslide == -128) channel->truepan = 32; else channel->truepan = MID(32, channel->truepan + channel->panslide*64, 32+255*64); } else { 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(channel); if (playing) { playing->slide += channel->portamento; 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); } // 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: sigrenderer->breakrow = 0; sigrenderer->processorder = entry->effectvalue - 1; sigrenderer->processrow = 0xFFFE; break; case IT_S: { unsigned char effectvalue = entry->effectvalue; if (effectvalue == 0) effectvalue = channel->lastS; channel->lastS = effectvalue; switch (effectvalue >> 4) { //case IT_S7: case IT_S_PATTERN_LOOP: { unsigned char v = effectvalue & 15; if (v == 0) channel->pat_loop_row = sigrenderer->processrow; else { if (channel->pat_loop_count == 0) { channel->pat_loop_count = v; sigrenderer->breakrow = channel->pat_loop_row; if (sigrenderer->sigdata->flags & 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 < 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) { sigrenderer->breakrow = channel->pat_loop_row; if (sigrenderer->sigdata->flags & 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 < 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) { 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; } } 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))) 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; } } static void it_compatible_gxx_retrigger(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) { channel->playing->volume_envelope.next_node = 0; channel->playing->volume_envelope.tick = 0; channel->playing->pan_envelope.next_node = 0; channel->playing->pan_envelope.tick = 0; 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 (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->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 (!(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) { DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; unsigned char nna; int i; 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 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 nna = channel->playing->instrument->new_note_action; #endif switch (nna) { case NNA_NOTE_CUT: free(channel->playing); channel->playing = NULL; 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; } } 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; } } /** 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; channel->playing->flags = 0; channel->playing->channel = channel; channel->playing->sample = &sigdata->sample[channel->sample-1]; if (sigdata->flags & IT_USE_INSTRUMENTS) channel->playing->instrument = &sigdata->instrument[channel->instrument-1]; else channel->playing->instrument = NULL; channel->playing->env_instrument = channel->playing->instrument; channel->playing->sampnum = channel->sample; channel->playing->instnum = channel->instrument; channel->playing->channel_volume = channel->channelvolume; channel->playing->note = channel->truenote; 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->tremolo_speed = 0; channel->playing->tremolo_depth = 0; channel->playing->tremolo_time = 0; channel->playing->sample_vibrato_time = 0; channel->playing->sample_vibrato_depth = 0; channel->playing->slide = 0; channel->playing->volume_envelope.next_node = 0; channel->playing->volume_envelope.tick = 0; channel->playing->pan_envelope.next_node = 0; channel->playing->pan_envelope.tick = 0; 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 (!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); } } } /* 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) sigrenderer->tick = sigrenderer->speed = entry->effectvalue; else if (sigdata->flags & IT_WAS_AN_XM) { 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; sigrenderer->processrow = 0xFFFE; 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) { 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 channel->portamento -= v << 4; } } break; case IT_PORTAMENTO_UP: { unsigned char v = entry->effectvalue; if (sigdata->flags & IT_WAS_AN_XM) { 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 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: { 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 (offset < end) it_playing_reset_resamplers(playing, offset); else if (sigdata->flags & IT_OLD_EFFECTS) it_playing_reset_resamplers(playing, end); } } } 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) p >>= 6; else { 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 (!IT_IS_SURROUND(channel->pan)) { 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(channel); } else update_retrig(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); 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: //case IT_S_SET_GLISSANDO_CONTROL: //case IT_S_FINETUNE: //case IT_S_SET_VIBRATO_WAVEFORM: //case IT_S_SET_TREMOLO_WAVEFORM: //case IT_S_SET_PANBRELLO_WAVEFORM: /* Waveforms for commands S3x, S4x and S5x: * 0: Sine wave * 1: Ramp down * 2: Square wave * 3: Random wave */ case IT_S_FINE_PATTERN_DELAY: sigrenderer->tick += effectvalue & 15; break; //case IT_S7: 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; break; case IT_S_SET_SURROUND_SOUND: if ((effectvalue & 15) == 1) { channel->pan = IT_SURROUND; channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; } 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) 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) channel->truepan = 32 + entry->effectvalue*64; else { channel->pan = (entry->effectvalue + 2) >> 2; channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; } break; //case IT_PANBRELLO: case IT_MIDI_MACRO: { 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; } } 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) 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->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) v = channel->lastEF; channel->lastEF = v; } if ((entry->mask & IT_ENTRY_NOTE) || ((sigdata->flags & IT_COMPATIBLE_GXX) && (entry->mask & IT_ENTRY_INSTRUMENT))) { 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); 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]; if (entry->mask & IT_ENTRY_INSTRUMENT) { channel->instrument = entry->instrument; instrument_to_sample(sigdata, channel); if (channel->playing) { /* 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; if (!(sigdata->flags & IT_WAS_A_MOD)) channel->truepan = 32 + channel->playing->sample->default_pan*64; retrigger_xm_envelopes(channel->playing); } } 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) { free(channel->playing); channel->playing = NULL; } 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); } channel->playing->flags = 0; channel->playing->channel = channel; channel->playing->sample = &sigdata->sample[channel->sample-1]; if (sigdata->flags & IT_USE_INSTRUMENTS) channel->playing->instrument = &sigdata->instrument[channel->instrument-1]; else channel->playing->instrument = NULL; channel->playing->env_instrument = channel->playing->instrument; channel->playing->sampnum = channel->sample; channel->playing->instnum = channel->instrument; channel->playing->channel_volume = channel->channelvolume; channel->playing->note = channel->truenote; 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->tremolo_speed = 0; channel->playing->tremolo_depth = 0; channel->playing->tremolo_time = 0; channel->playing->sample_vibrato_time = 0; channel->playing->sample_vibrato_depth = 0; channel->playing->slide = 0; 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 | 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->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->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_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) channel->volume = 0; else if (channel->playing) { free(channel->playing); channel->playing = NULL; } } } 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) { if (!(envelope->flags & IT_ENVELOPE_ON)) 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)) { 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); update_it_envelope(playing, &playing->env_instrument->pitch_envelope, &playing->pitch_envelope); } 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 void process_playing(DUMB_IT_SIGDATA *sigdata, IT_PLAYING *playing) { if (playing->instrument) { if (sigdata->flags & IT_WAS_AN_XM) update_xm_envelopes(playing); else update_it_envelopes(playing); update_fadeout(sigdata, playing); } //Calculate final volume if required //Calculate final pan if required 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 void process_all_playing(DUMB_IT_SIGRENDERER *sigrenderer) { DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; int i; 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 = it_sine[playing->vibrato_time]; 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 (sigdata->flags & IT_LINEAR_SLIDES) { int currpitch = ((playing->note - 60) << 8) + playing->slide + vibrato_shift; /* 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 / 65536.0f; } else { int slide = playing->slide + vibrato_shift; playing->delta = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note); /* 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; continue; } playing->delta = (1.0f / 65536.0f) / playing->delta; } 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(sigdata, sigrenderer->channel[i].playing); 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(sigdata, sigrenderer->playing[i]); 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; sigrenderer->processrow++; if (sigrenderer->processrow >= sigrenderer->n_rows) { IT_PATTERN *pattern; int n; int processorder = sigrenderer->processorder; if (sigrenderer->processrow == 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 = sigdata->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) sigrenderer->processorder = -1; #else if (n == IT_ORDER_END) sigrenderer->processorder = -1; #endif } 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. */ if (n && (processorder == 0xFFFF ? sigrenderer->order > sigrenderer->processorder : sigrenderer->order >= sigrenderer->processorder)) { if (sigrenderer->callbacks->loop) { if ((*sigrenderer->callbacks->loop)(sigrenderer->callbacks->loop_data)) return 1; 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 { sigrenderer->entry = sigrenderer->entry_start; sigrenderer->row = 0; } } 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)) 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. */ } update_effects(sigrenderer); } } else { speed0: update_effects(sigrenderer); update_tick_counts(sigrenderer); } 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 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; vol = it_sine[playing->tremolo_time]; vol *= playing->tremolo_depth; vol = (playing->volume << 5) + vol; if (vol <= 0) return 0; if (vol > 64 << 5) vol = 64 << 5; 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->env_instrument->volume_envelope.flags & IT_ENVELOPE_ON) { 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) { int pan = playing->pan; if (pan <= 64 << IT_ENVELOPE_SHIFT && playing->env_instrument && (playing->env_instrument->pan_envelope.flags & IT_ENVELOPE_ON)) { 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; } /* 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 delta, long pos, long size, sample_t **samples, int store_end_sample, int *left_to_mix) { int bits; int pan; float span; /* separated pan, range -1 to 1; garbage for surround */ long size_rendered; if (playing->flags & IT_PLAYING_DEAD) return 0; if (*left_to_mix <= 0) volume = 0; bits = playing->sample->flags & IT_SAMPLE_16BIT ? 16 : 8; pan = apply_pan_envelope(playing); span = (pan - (32<<8)) * sigrenderer->sigdata->pan_separation * (1.0f / ((32<<8) * 128)); 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 { if (sigrenderer->n_channels == 2) { float lvol, rvol; lvol = volume; if (!IT_IS_SURROUND_SHIFTED(pan)) lvol *= 1.0f - span; rvol = -lvol; if (!IT_IS_SURROUND_SHIFTED(pan)) rvol += 2.0f * volume; if (playing->sample->flags & IT_SAMPLE_STEREO) { if (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 (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 (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 (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) { float lvol, rvol; lvol = 0.5f * volume; if (!IT_IS_SURROUND_SHIFTED(pan)) lvol *= 1.0f - span; rvol = lvol; if (!IT_IS_SURROUND_SHIFTED(pan)) rvol = volume - rvol; if (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 (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 (sigrenderer->click_remover) { sample_t click; dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, volume, &click); dumb_record_click(sigrenderer->click_remover[0], pos, click); } size_rendered = dumb_resample_n_1_1(bits, &playing->resampler, samples[0] + pos, size, volume, delta); if (store_end_sample) dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, volume, &samples[0][pos + size_rendered]); if (sigrenderer->click_remover) { sample_t click; dumb_resample_get_current_sample_n_1_1(bits, &playing->resampler, volume, &click); dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click); } } } (*left_to_mix)--; } if (playing->resampler.dir == 0) playing->flags |= IT_PLAYING_DEAD; return size_rendered; } 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 = it_sine[playing->sample_vibrato_time]; 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; *delta *= (float)pow(DUMB_PITCH_BASE, sample_vibrato_shift); } if (playing->env_instrument && (playing->env_instrument->pitch_envelope.flags & IT_ENVELOPE_ON)) { 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<> (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; 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; apply_pitch_modifications(sigrenderer->sigdata, playing, ¬e_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 (to_mix[i].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(sigrenderer, playing, 0, note_delta, pos, size, NULL, 0, &left_to_mix); 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(sigrenderer, playing, to_mix[i].volume, note_delta, 0, size, samples_to_filter, 1, &left_to_mix); sigrenderer->click_remover = cr; if (sigrenderer->n_channels == 2) { it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[0], 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]+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], 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(sigrenderer, playing, to_mix[i].volume, note_delta, pos, size, samples, 0, &left_to_mix); } } 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 (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 (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->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->note = 0; channel->SFmacro = 0; channel->filter_cutoff = 127; channel->filter_resonance = 0; channel->xm_retrig = 0; channel->retrig_tick = 0; channel->tremor_time = 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->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; } 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->pat_loop_row = -1; sigrenderer->rowcount = 1; sigrenderer->order = startorder; 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; return sigrenderer; } 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; } } 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; 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); 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); 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); 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 */ /* Returns the length of the module, up until it first loops. */ long dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata) { 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, 0); 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; 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; } } 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)); } }