ref: fb758de4fe3e5dcfa9f98bf65ff1be72ed9c678f
dir: /src/it/itrender.c/
/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque * / \ * / . \ * itrender.c - Code to render an Impulse Tracker / / \ \ * module. | < / \_ * | \/ /\ / * Written - painstakingly - by entheh. \_ / > / * | \ / / * | ' / * \__/ */ #include <math.h> #include <stdlib.h> #include <string.h> #include "dumb.h" #include "internal/dumb.h" #include "internal/it.h" #include "internal/lpc.h" #include "internal/resampler.h" // Keep this disabled, as it's actually slower than the original C/integer // version // //#ifdef __APPLE__ //#include <TargetConditionals.h> //#if TARGET_CPU_ARM || TARGET_CPU_ARM64 //#include <arm_neon.h> //#define FILTER_NEON //#endif //#endif // #define BIT_ARRAY_BULLSHIT static IT_PLAYING *new_playing() { IT_PLAYING *r = (IT_PLAYING *)malloc(sizeof(*r)); if (r) { r->resampler.fir_resampler_ratio = 0.0; r->resampler.fir_resampler[0] = resampler_create(); if (!r->resampler.fir_resampler[0]) { free(r); return NULL; } r->resampler.fir_resampler[1] = resampler_create(); if (!r->resampler.fir_resampler[1]) { resampler_delete(r->resampler.fir_resampler[0]); free(r); return NULL; } } return r; } static void free_playing(IT_PLAYING *r) { resampler_delete(r->resampler.fir_resampler[1]); resampler_delete(r->resampler.fir_resampler[0]); free(r); } static IT_PLAYING *dup_playing(IT_PLAYING *src, IT_CHANNEL *dstchannel, IT_CHANNEL *srcchannel) { IT_PLAYING *dst; if (!src) return NULL; dst = malloc(sizeof(*dst)); if (!dst) return NULL; dst->flags = src->flags; dst->resampling_quality = src->resampling_quality; ASSERT(src->channel); dst->channel = &dstchannel[src->channel - srcchannel]; dst->sample = src->sample; dst->instrument = src->instrument; dst->env_instrument = src->env_instrument; dst->sampnum = src->sampnum; dst->instnum = src->instnum; dst->declick_stage = src->declick_stage; dst->float_volume[0] = src->float_volume[0]; dst->float_volume[1] = src->float_volume[1]; dst->ramp_volume[0] = src->ramp_volume[0]; dst->ramp_volume[1] = src->ramp_volume[1]; dst->ramp_delta[0] = src->ramp_delta[0]; dst->ramp_delta[1] = src->ramp_delta[1]; dst->channel_volume = src->channel_volume; dst->volume = src->volume; dst->pan = src->pan; dst->volume_offset = src->volume_offset; dst->panning_offset = src->panning_offset; dst->note = src->note; dst->enabled_envelopes = src->enabled_envelopes; dst->filter_cutoff = src->filter_cutoff; dst->filter_resonance = src->filter_resonance; dst->true_filter_cutoff = src->true_filter_cutoff; dst->true_filter_resonance = src->true_filter_resonance; dst->vibrato_speed = src->vibrato_speed; dst->vibrato_depth = src->vibrato_depth; dst->vibrato_n = src->vibrato_n; dst->vibrato_time = src->vibrato_time; dst->vibrato_waveform = src->vibrato_waveform; dst->tremolo_speed = src->tremolo_speed; dst->tremolo_depth = src->tremolo_depth; dst->tremolo_time = src->tremolo_time; dst->tremolo_waveform = src->tremolo_waveform; dst->panbrello_speed = src->panbrello_speed; dst->panbrello_depth = src->panbrello_depth; dst->panbrello_time = src->panbrello_time; dst->panbrello_waveform = src->panbrello_waveform; dst->panbrello_random = src->panbrello_random; dst->sample_vibrato_time = src->sample_vibrato_time; dst->sample_vibrato_waveform = src->sample_vibrato_waveform; dst->sample_vibrato_depth = src->sample_vibrato_depth; dst->slide = src->slide; dst->delta = src->delta; dst->finetune = src->finetune; dst->volume_envelope = src->volume_envelope; dst->pan_envelope = src->pan_envelope; dst->pitch_envelope = src->pitch_envelope; dst->fadeoutcount = src->fadeoutcount; dst->filter_state[0] = src->filter_state[0]; dst->filter_state[1] = src->filter_state[1]; dst->resampler = src->resampler; dst->resampler.pickup_data = dst; dst->resampler.fir_resampler_ratio = src->resampler.fir_resampler_ratio; dst->resampler.fir_resampler[0] = resampler_dup(src->resampler.fir_resampler[0]); if (!dst->resampler.fir_resampler[0]) { free(dst); return NULL; } dst->resampler.fir_resampler[1] = resampler_dup(src->resampler.fir_resampler[1]); if (!dst->resampler.fir_resampler[1]) { resampler_delete(dst->resampler.fir_resampler[0]); free(dst); return NULL; } dst->time_lost = src->time_lost; // dst->output = src->output; return dst; } static void dup_channel(IT_CHANNEL *dst, IT_CHANNEL *src) { dst->flags = src->flags; dst->volume = src->volume; dst->volslide = src->volslide; dst->xm_volslide = src->xm_volslide; dst->panslide = src->panslide; dst->pan = src->pan; dst->truepan = src->truepan; dst->channelvolume = src->channelvolume; dst->channelvolslide = src->channelvolslide; dst->instrument = src->instrument; dst->note = src->note; dst->SFmacro = src->SFmacro; dst->filter_cutoff = src->filter_cutoff; dst->filter_resonance = src->filter_resonance; dst->key_off_count = src->key_off_count; dst->note_cut_count = src->note_cut_count; dst->note_delay_count = src->note_delay_count; dst->note_delay_entry = src->note_delay_entry; dst->new_note_action = src->new_note_action; dst->arpeggio_table = src->arpeggio_table; memcpy(dst->arpeggio_offsets, src->arpeggio_offsets, sizeof(dst->arpeggio_offsets)); dst->retrig = src->retrig; dst->xm_retrig = src->xm_retrig; dst->retrig_tick = src->retrig_tick; dst->tremor_time = src->tremor_time; dst->vibrato_waveform = src->vibrato_waveform; dst->tremolo_waveform = src->tremolo_waveform; dst->panbrello_waveform = src->panbrello_waveform; dst->portamento = src->portamento; dst->toneporta = src->toneporta; dst->toneslide = src->toneslide; dst->toneslide_tick = src->toneslide_tick; dst->last_toneslide_tick = src->last_toneslide_tick; dst->ptm_toneslide = src->ptm_toneslide; dst->ptm_last_toneslide = src->ptm_last_toneslide; dst->okt_toneslide = src->okt_toneslide; dst->destnote = src->destnote; dst->glissando = src->glissando; dst->sample = src->sample; dst->truenote = src->truenote; dst->midi_state = src->midi_state; dst->lastvolslide = src->lastvolslide; dst->lastDKL = src->lastDKL; dst->lastEF = src->lastEF; dst->lastG = src->lastG; dst->lastHspeed = src->lastHspeed; dst->lastHdepth = src->lastHdepth; dst->lastRspeed = src->lastRspeed; dst->lastRdepth = src->lastRdepth; dst->lastYspeed = src->lastYspeed; dst->lastYdepth = src->lastYdepth; dst->lastI = src->lastI; dst->lastJ = src->lastJ; dst->lastN = src->lastN; dst->lastO = src->lastO; dst->high_offset = src->high_offset; dst->lastP = src->lastP; dst->lastQ = src->lastQ; dst->lastS = src->lastS; dst->pat_loop_row = src->pat_loop_row; dst->pat_loop_count = src->pat_loop_count; dst->pat_loop_end_row = src->pat_loop_end_row; dst->lastW = src->lastW; dst->xm_lastE1 = src->xm_lastE1; dst->xm_lastE2 = src->xm_lastE2; dst->xm_lastEA = src->xm_lastEA; dst->xm_lastEB = src->xm_lastEB; dst->xm_lastX1 = src->xm_lastX1; dst->xm_lastX2 = src->xm_lastX2; dst->inv_loop_delay = src->inv_loop_delay; dst->inv_loop_speed = src->inv_loop_speed; dst->inv_loop_offset = src->inv_loop_offset; dst->playing = dup_playing(src->playing, dst, src); #ifdef BIT_ARRAY_BULLSHIT dst->played_patjump = bit_array_dup(src->played_patjump); dst->played_patjump_order = src->played_patjump_order; #endif // dst->output = src->output; } /* Allocate the new callbacks first, then pass them to this function! * It will free them on failure. */ static DUMB_IT_SIGRENDERER *dup_sigrenderer(DUMB_IT_SIGRENDERER *src, int n_channels, IT_CALLBACKS *callbacks) { DUMB_IT_SIGRENDERER *dst; int i; if (!src) { if (callbacks) free(callbacks); return NULL; } dst = malloc(sizeof(*dst)); if (!dst) { if (callbacks) free(callbacks); return NULL; } dst->sigdata = src->sigdata; dst->n_channels = n_channels; dst->resampling_quality = src->resampling_quality; dst->globalvolume = src->globalvolume; dst->globalvolslide = src->globalvolslide; dst->tempo = src->tempo; dst->temposlide = src->temposlide; for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dup_channel(&dst->channel[i], &src->channel[i]); for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) dst->playing[i] = dup_playing(src->playing[i], dst->channel, src->channel); dst->tick = src->tick; dst->speed = src->speed; dst->rowcount = src->rowcount; dst->order = src->order; dst->row = src->row; dst->processorder = src->processorder; dst->processrow = src->processrow; dst->breakrow = src->breakrow; dst->restart_position = src->restart_position; dst->n_rows = src->n_rows; dst->entry_start = src->entry_start; dst->entry = src->entry; dst->entry_end = src->entry_end; dst->time_left = src->time_left; dst->sub_time_left = src->sub_time_left; dst->ramp_style = src->ramp_style; dst->click_remover = NULL; dst->callbacks = callbacks; #ifdef BIT_ARRAY_BULLSHIT dst->played = bit_array_dup(src->played); dst->looped = src->looped; dst->time_played = src->time_played; dst->row_timekeeper = timekeeping_array_dup(src->row_timekeeper); #endif dst->gvz_time = src->gvz_time; dst->gvz_sub_time = src->gvz_sub_time; // dst->max_output = src->max_output; return dst; } static const IT_MIDI default_midi = { /* unsigned char SFmacro[16][16]; */ {{0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, /* unsigned char SFmacrolen[16]; */ {4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* unsigned short SFmacroz[16]; */ /* Bitfield; bit 0 set = z in first position */ {0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* unsigned char Zmacro[128][16]; */ {{0xF0, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0xF0, 0xF0, 0x01, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, /* unsigned char Zmacrolen[128]; */ {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; static void it_reset_filter_state(IT_FILTER_STATE *state) { state->currsample = 0; state->prevsample = 0; } #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_int(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, long pos, sample_t *src, long size, int step, int sampfreq, int cutoff, int resonance) { sample_t currsample = state->currsample; sample_t prevsample = state->prevsample; float a, b, c; long datasize; { float inv_angle = (float)(sampfreq * pow(0.5, 0.25 + cutoff * (1.0 / (24 << IT_ENVELOPE_SHIFT))) * (1.0 / (2 * 3.14159265358979323846 * 110.0))); float loss = (float)exp(resonance * (-LOG10 * 1.2 / 128.0)); float d, e; #if 0 loss *= 2; // This is the mistake most players seem to make! #endif #if 1 d = (1.0f - loss) / inv_angle; if (d > 2.0f) d = 2.0f; d = (loss - d) * inv_angle; e = inv_angle * inv_angle; a = 1.0f / (1.0f + d + e); c = -e * a; b = 1.0f - a - c; #else a = 1.0f / (inv_angle * inv_angle + inv_angle * loss + loss); c = -(inv_angle * inv_angle) * a; b = 1.0f - a - c; #endif } dst += pos * step; datasize = size * step; #define INT_FILTERS #ifdef INT_FILTERS #define MULSCA(a, b) ((int)((LONG_LONG)((a) << 4) * (b) >> 32)) #define SCALEB 12 { int ai = (int)(a * (1 << (16 + SCALEB))); int bi = (int)(b * (1 << (16 + SCALEB))); int ci = (int)(c * (1 << (16 + SCALEB))); int i; if (cr) { sample_t startstep = MULSCA(src[0], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci); dumb_record_click(cr, pos, startstep); } for (i = 0; i < datasize; i += step) { { sample_t newsample = MULSCA(src[i], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci); prevsample = currsample; currsample = newsample; } dst[i] += currsample; } if (cr) { sample_t endstep = MULSCA(src[datasize], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci); dumb_record_click(cr, pos + size, -endstep); } } #else #error This version is broken - it does not use step, and state should contain floats for it if (cr) { float startstep = src[0] * a + currsample * b + prevsample * c; dumb_record_click(cr, pos, (sample_t)startstep); } { int i = size % 3; while (i > 0) { { float newsample = *src++ * a + currsample * b + prevsample * c; prevsample = currsample; currsample = newsample; } *dst++ += (sample_t)currsample; i--; } i = size / 3; while (i > 0) { float newsample; /* Gotta love unrolled loops! */ *dst++ += (sample_t)(newsample = *src++ * a + currsample * b + prevsample * c); *dst++ += (sample_t)(prevsample = *src++ * a + newsample * b + currsample * c); *dst++ += (sample_t)(currsample = *src++ * a + prevsample * b + newsample * c); i--; } } if (cr) { float endstep = src[datasize] * a + currsample * b + prevsample * c; dumb_record_click(cr, pos + size, -(sample_t)endstep); } #endif state->currsample = currsample; state->prevsample = prevsample; } #if defined(_USE_SSE) && (defined(_M_IX86) || defined(__i386__) || \ defined(_M_X64) || defined(__amd64__)) #include <xmmintrin.h> static void it_filter_sse(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) { __m128 data, impulse; __m128 temp1, temp2; sample_t currsample = state->currsample; sample_t prevsample = state->prevsample; float imp[4]; // profiler( filter_sse ); On ClawHammer Athlon64 3200+, ~12000 cycles, ~500 // for that x87 setup code (as opposed to ~25500 for the original integer // code) long datasize; { float inv_angle = (float)(sampfreq * pow(0.5, 0.25 + cutoff * (1.0 / (24 << IT_ENVELOPE_SHIFT))) * (1.0 / (2 * 3.14159265358979323846 * 110.0))); float loss = (float)exp(resonance * (-LOG10 * 1.2 / 128.0)); float d, e; #if 0 loss *= 2; // This is the mistake most players seem to make! #endif #if 1 d = (1.0f - loss) / inv_angle; if (d > 2.0f) d = 2.0f; d = (loss - d) * inv_angle; e = inv_angle * inv_angle; imp[0] = 1.0f / (1.0f + d + e); imp[2] = -e * imp[0]; imp[1] = 1.0f - imp[0] - imp[2]; #else imp[0] = 1.0f / (inv_angle * inv_angle + inv_angle * loss + loss); imp[2] = -(inv_angle * inv_angle) * imp[0]; imp[1] = 1.0f - imp[0] - imp[2]; #endif imp[3] = 0.0f; } dst += pos * step; datasize = size * step; { int ai, bi, ci, i; if (cr) { sample_t startstep; ai = (int)(imp[0] * (1 << (16 + SCALEB))); bi = (int)(imp[1] * (1 << (16 + SCALEB))); ci = (int)(imp[2] * (1 << (16 + SCALEB))); startstep = MULSCA(src[0], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci); dumb_record_click(cr, pos, startstep); } temp1 = _mm_setzero_ps(); data = _mm_cvtsi32_ss(temp1, currsample); temp2 = _mm_cvtsi32_ss(temp1, prevsample); impulse = _mm_loadu_ps((const float *)&imp); data = _mm_shuffle_ps(data, temp2, _MM_SHUFFLE(1, 0, 0, 1)); for (i = 0; i < datasize; i += step) { temp1 = _mm_cvtsi32_ss(data, src[i]); temp1 = _mm_mul_ps(temp1, impulse); temp2 = _mm_movehl_ps(temp2, temp1); temp1 = _mm_add_ps(temp1, temp2); temp2 = temp1; temp2 = _mm_shuffle_ps(temp2, temp1, _MM_SHUFFLE(0, 0, 0, 1)); temp1 = _mm_add_ps(temp1, temp2); temp1 = _mm_shuffle_ps(temp1, data, _MM_SHUFFLE(2, 1, 0, 0)); data = temp1; dst[i] += _mm_cvtss_si32(temp1); } currsample = _mm_cvtss_si32(temp1); temp1 = _mm_shuffle_ps(temp1, data, _MM_SHUFFLE(0, 0, 0, 2)); prevsample = _mm_cvtss_si32(temp1); if (cr) { sample_t endstep = MULSCA(src[datasize], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci); dumb_record_click(cr, pos + size, -endstep); } } state->currsample = currsample; state->prevsample = prevsample; } #endif #ifdef FILTER_NEON static void it_filter_neon(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) { float32x4_t data, impulse; float32x4_t temp1; float32x2_t temp2; float32_t temp3; sample_t currsample = state->currsample; sample_t prevsample = state->prevsample; float imp[4]; // profiler( filter_sse ); On ClawHammer Athlon64 3200+, ~12000 cycles, ~500 // for that x87 setup code (as opposed to ~25500 for the original integer // code) long datasize; { float inv_angle = (float)(sampfreq * pow(0.5, 0.25 + cutoff * (1.0 / (24 << IT_ENVELOPE_SHIFT))) * (1.0 / (2 * 3.14159265358979323846 * 110.0))); float loss = (float)exp(resonance * (-LOG10 * 1.2 / 128.0)); float d, e; #if 0 loss *= 2; // This is the mistake most players seem to make! #endif #if 1 d = (1.0f - loss) / inv_angle; if (d > 2.0f) d = 2.0f; d = (loss - d) * inv_angle; e = inv_angle * inv_angle; imp[0] = 1.0f / (1.0f + d + e); imp[2] = -e * imp[0]; imp[1] = 1.0f - imp[0] - imp[2]; #else imp[0] = 1.0f / (inv_angle * inv_angle + inv_angle * loss + loss); imp[2] = -(inv_angle * inv_angle) * imp[0]; imp[1] = 1.0f - imp[0] - imp[2]; #endif imp[3] = 0.0f; } dst += pos * step; datasize = size * step; { int ai, bi, ci, i; if (cr) { sample_t startstep; ai = (int)(imp[0] * (1 << (16 + SCALEB))); bi = (int)(imp[1] * (1 << (16 + SCALEB))); ci = (int)(imp[2] * (1 << (16 + SCALEB))); startstep = MULSCA(src[0], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci); dumb_record_click(cr, pos, startstep); } data = vdupq_n_f32(0.0f); data = vsetq_lane_f32(currsample, data, 1); data = vsetq_lane_f32(prevsample, data, 2); impulse = vld1q_f32((const float32_t *)&imp); for (i = 0; i < datasize; i += step) { data = vsetq_lane_f32(src[i], data, 0); temp1 = vmulq_f32(data, impulse); temp2 = vadd_f32(vget_high_f32(temp1), vget_low_f32(temp1)); temp3 = vget_lane_f32(vpadd_f32(temp2, temp2), 0); data = vextq_f32(data, data, 3); data = vsetq_lane_f32(temp3, data, 1); dst[i] += temp3; } currsample = temp3; prevsample = vgetq_lane_f32(data, 2); if (cr) { sample_t endstep = MULSCA(src[datasize], ai) + MULSCA(currsample, bi) + MULSCA(prevsample, ci); dumb_record_click(cr, pos + size, -endstep); } } state->currsample = currsample; state->prevsample = prevsample; } #endif #undef LOG10 #ifdef _USE_SSE #if defined(_M_IX86) || defined(__i386__) #ifdef _MSC_VER #include <intrin.h> #elif defined(__clang__) || defined(__GNUC__) static inline void __cpuid(int *data, int selector) { #if defined(__PIC__) && defined(__i386__) asm("xchgl %%ebx, %%esi; cpuid; xchgl %%ebx, %%esi" : "=a"(data[0]), "=S"(data[1]), "=c"(data[2]), "=d"(data[3]) : "0"(selector)); #elif defined(__PIC__) && defined(__amd64__) asm("xchg{q} {%%}rbx, %q1; cpuid; xchg{q} {%%}rbx, %q1" : "=a"(data[0]), "=&r"(data[1]), "=c"(data[2]), "=d"(data[3]) : "0"(selector)); #else asm("cpuid" : "=a"(data[0]), "=b"(data[1]), "=c"(data[2]), "=d"(data[3]) : "a"(selector)); #endif } #else #define __cpuid(a, b) memset((a), 0, sizeof(int) * 4) #endif static int query_cpu_feature_sse() { int buffer[4]; __cpuid(buffer, 1); if ((buffer[3] & (1 << 25)) == 0) return 0; return 1; } static int _dumb_it_use_sse = 0; void _dumb_init_sse() { static int initialized = 0; if (!initialized) { _dumb_it_use_sse = query_cpu_feature_sse(); initialized = 1; } } #elif defined(_M_X64) || defined(__amd64__) static const int _dumb_it_use_sse = 1; void _dumb_init_sse() {} #else static const int _dumb_it_use_sse = 0; void _dumb_init_sse() {} #endif #endif 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) { #if defined(_USE_SSE) && (defined(_M_IX86) || defined(__i386__) || \ defined(_M_X64) || defined(__amd64__)) _dumb_init_sse(); if (_dumb_it_use_sse) it_filter_sse(cr, state, dst, pos, src, size, step, sampfreq, cutoff, resonance); else #endif #ifdef FILTER_NEON it_filter_neon(cr, state, dst, pos, src, size, step, sampfreq, cutoff, resonance); #else it_filter_int(cr, state, dst, pos, src, size, step, sampfreq, cutoff, resonance); #endif } static const signed char it_sine[256] = { 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23, 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60, 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26, 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2, 0, -2, -3, -5, -6, -8, -9, -11, -12, -14, -16, -17, -19, -20, -22, -23, -24, -26, -27, -29, -30, -32, -33, -34, -36, -37, -38, -39, -41, -42, -43, -44, -45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -56, -57, -58, -59, -59, -60, -60, -61, -61, -62, -62, -62, -63, -63, -63, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -63, -63, -63, -62, -62, -62, -61, -61, -60, -60, -59, -59, -58, -57, -56, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -39, -38, -37, -36, -34, -33, -32, -30, -29, -27, -26, -24, -23, -22, -20, -19, -17, -16, -14, -12, -11, -9, -8, -6, -5, -3, -2}; #if 1 /** WARNING: use these! */ /** JULIEN: Plus for XM compatibility it could be interesting to rename * it_sawtooth[] to it_rampdown[], and add an it_rampup[]. * Also, still for XM compat', twood be good if it was possible to tell the * the player not to retrig' the waveform on a new instrument. * Both of these are only for completness though, as I don't think it would * be very noticeable ;) */ /** ENTHEH: IT also has the 'don't retrig' thingy :) */ static const signed char it_sawtooth[256] = { 64, 63, 63, 62, 62, 61, 61, 60, 60, 59, 59, 58, 58, 57, 57, 56, 56, 55, 55, 54, 54, 53, 53, 52, 52, 51, 51, 50, 50, 49, 49, 48, 48, 47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 40, 40, 39, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 32, 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, 26, 25, 25, 24, 24, 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16, 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0, -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6, -7, -7, -8, -8, -9, -9, -10, -10, -11, -11, -12, -12, -13, -13, -14, -14, -15, -15, -16, -16, -17, -17, -18, -18, -19, -19, -20, -20, -21, -21, -22, -22, -23, -23, -24, -24, -25, -25, -26, -26, -27, -27, -28, -28, -29, -29, -30, -30, -31, -31, -32, -32, -33, -33, -34, -34, -35, -35, -36, -36, -37, -37, -38, -38, -39, -39, -40, -40, -41, -41, -42, -42, -43, -43, -44, -44, -45, -45, -46, -46, -47, -47, -48, -48, -49, -49, -50, -50, -51, -51, -52, -52, -53, -53, -54, -54, -55, -55, -56, -56, -57, -57, -58, -58, -59, -59, -60, -60, -61, -61, -62, -62, -63, -63, -64}; static const signed char it_squarewave[256] = { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const signed char it_xm_ramp[256] = { 0, -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6, -7, -7, -8, -8, -9, -9, -10, -10, -11, -11, -12, -12, -13, -13, -14, -14, -15, -15, -16, -16, -17, -17, -18, -18, -19, -19, -20, -20, -21, -21, -22, -22, -23, -23, -24, -24, -25, -25, -26, -26, -27, -27, -28, -28, -29, -29, -30, -30, -31, -31, -32, -32, -33, -33, -34, -34, -35, -35, -36, -36, -37, -37, -38, -38, -39, -39, -40, -40, -41, -41, -42, -42, -43, -43, -44, -44, -45, -45, -46, -46, -47, -47, -48, -48, -49, -49, -50, -50, -51, -51, -52, -52, -53, -53, -54, -54, -55, -55, -56, -56, -57, -57, -58, -58, -59, -59, -60, -60, -61, -61, -62, -62, -63, -63, -64, 64, 63, 63, 62, 62, 61, 61, 60, 60, 59, 59, 58, 58, 57, 57, 56, 56, 55, 55, 54, 54, 53, 53, 52, 52, 51, 51, 50, 50, 49, 49, 48, 48, 47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 40, 40, 39, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 32, 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, 26, 25, 25, 24, 24, 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16, 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0}; static const signed char it_xm_squarewave[256] = { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64}; #endif static void reset_tick_counts(DUMB_IT_SIGRENDERER *sigrenderer) { int i; for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { IT_CHANNEL *channel = &sigrenderer->channel[i]; channel->key_off_count = 0; channel->note_cut_count = 0; channel->note_delay_count = 0; } } static const unsigned char arpeggio_mod[32] = {0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1}; static const unsigned char arpeggio_xm[32] = {0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; static const unsigned char arpeggio_okt_3[32] = { 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0}; static const unsigned char arpeggio_okt_4[32] = { 0, 2, 0, 1, 0, 2, 0, 1, 0, 2, 0, 1, 0, 2, 0, 1, 0, 2, 0, 1, 0, 2, 0, 1, 0, 2, 0, 1, 0, 2, 0, 1}; static const unsigned char arpeggio_okt_5[32] = { 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2}; static void reset_channel_effects(IT_CHANNEL *channel) { channel->volslide = 0; channel->xm_volslide = 0; channel->panslide = 0; channel->channelvolslide = 0; channel->arpeggio_table = (const unsigned char *)&arpeggio_mod; memset(channel->arpeggio_offsets, 0, sizeof(channel->arpeggio_offsets)); channel->retrig = 0; if (channel->xm_retrig) { channel->xm_retrig = 0; channel->retrig_tick = 0; } channel->tremor_time &= 127; channel->portamento = 0; channel->toneporta = 0; if (channel->ptm_toneslide) { channel->ptm_last_toneslide = channel->ptm_toneslide; channel->last_toneslide_tick = channel->toneslide_tick; } else channel->ptm_last_toneslide = 0; channel->ptm_toneslide = 0; channel->toneslide_tick = 0; channel->okt_toneslide = 0; if (channel->playing) { channel->playing->vibrato_n = 0; channel->playing->tremolo_speed = 0; channel->playing->tremolo_depth = 0; channel->playing->panbrello_speed = 0; } } static void reset_effects(DUMB_IT_SIGRENDERER *sigrenderer) { int i; sigrenderer->globalvolslide = 0; sigrenderer->temposlide = 0; for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { reset_channel_effects(&sigrenderer->channel[i]); } } static void update_tremor(IT_CHANNEL *channel) { if ((channel->tremor_time & 128) && channel->playing) { if (channel->tremor_time == 128) channel->tremor_time = (channel->lastI >> 4) | 192; else if (channel->tremor_time == 192) channel->tremor_time = (channel->lastI & 15) | 128; else channel->tremor_time--; } } static void it_pickup_loop(DUMB_RESAMPLER *resampler, void *data) { resampler->pos -= resampler->end - resampler->start; ((IT_PLAYING *)data)->time_lost += resampler->end - resampler->start; } static void it_pickup_pingpong_loop(DUMB_RESAMPLER *resampler, void *data) { if (resampler->dir < 0) { resampler->pos = (resampler->start << 1) - 1 - resampler->pos; resampler->subpos ^= 65535; resampler->dir = 1; ((IT_PLAYING *)data)->time_lost += (resampler->end - resampler->start) << 1; } else { resampler->pos = (resampler->end << 1) - 1 - resampler->pos; resampler->subpos ^= 65535; resampler->dir = -1; } } static void it_pickup_stop_at_end(DUMB_RESAMPLER *resampler, void *data) { (void)data; if (resampler->dir < 0) { resampler->pos = (resampler->start << 1) - 1 - resampler->pos; resampler->subpos ^= 65535; /* By rights, time_lost would be updated here. However, there is no * need at this point; it will not be used. * * ((IT_PLAYING *)data)->time_lost += (resampler->src_end - * resampler->src_start) << 1; */ resampler->dir = 1; } else resampler->dir = 0; } static void it_pickup_stop_after_reverse(DUMB_RESAMPLER *resampler, void *data) { (void)data; resampler->dir = 0; } static void it_playing_update_resamplers(IT_PLAYING *playing) { if ((playing->sample->flags & IT_SAMPLE_SUS_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) { playing->resampler.start = playing->sample->sus_loop_start; playing->resampler.end = playing->sample->sus_loop_end; if (playing->resampler.start == playing->resampler.end) playing->resampler.pickup = &it_pickup_stop_at_end; else if (playing->sample->flags & IT_SAMPLE_PINGPONG_SUS_LOOP) playing->resampler.pickup = &it_pickup_pingpong_loop; else playing->resampler.pickup = &it_pickup_loop; } else if (playing->sample->flags & IT_SAMPLE_LOOP) { playing->resampler.start = playing->sample->loop_start; playing->resampler.end = playing->sample->loop_end; if (playing->resampler.start == playing->resampler.end) playing->resampler.pickup = &it_pickup_stop_at_end; else if (playing->sample->flags & IT_SAMPLE_PINGPONG_LOOP) playing->resampler.pickup = &it_pickup_pingpong_loop; else playing->resampler.pickup = &it_pickup_loop; } else if (playing->flags & IT_PLAYING_REVERSE) { playing->resampler.start = 0; playing->resampler.end = playing->sample->length; playing->resampler.dir = -1; playing->resampler.pickup = &it_pickup_stop_after_reverse; } else { if (playing->sample->flags & IT_SAMPLE_SUS_LOOP) playing->resampler.start = playing->sample->sus_loop_start; else playing->resampler.start = 0; playing->resampler.end = playing->sample->length; playing->resampler.pickup = &it_pickup_stop_at_end; } ASSERT(playing->resampler.pickup_data == playing); } /* This should be called whenever the sample or sample position changes. */ static void it_playing_reset_resamplers(IT_PLAYING *playing, long pos) { int bits = playing->sample->flags & IT_SAMPLE_16BIT ? 16 : 8; int quality = playing->resampling_quality; int channels = playing->sample->flags & IT_SAMPLE_STEREO ? 2 : 1; if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality) quality = playing->sample->max_resampling_quality; dumb_reset_resampler_n(bits, &playing->resampler, playing->sample->data, channels, pos, 0, 0, quality); playing->resampler.pickup_data = playing; playing->time_lost = 0; playing->flags &= ~IT_PLAYING_DEAD; it_playing_update_resamplers(playing); } static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel); /* Should we only be retriggering short samples on XM? */ static void update_retrig(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel) { if (channel->xm_retrig) { channel->retrig_tick--; if (channel->retrig_tick <= 0) { if (channel->playing) { it_playing_reset_resamplers(channel->playing, 0); channel->playing->declick_stage = 0; } else if (sigrenderer->sigdata->flags & IT_WAS_AN_XM) it_retrigger_note(sigrenderer, channel); channel->retrig_tick = channel->xm_retrig; } } else if (channel->retrig & 0x0F) { channel->retrig_tick--; if (channel->retrig_tick <= 0) { if (channel->retrig < 0x10) { } else if (channel->retrig < 0x20) { channel->volume--; if (channel->volume > 64) channel->volume = 0; } else if (channel->retrig < 0x30) { channel->volume -= 2; if (channel->volume > 64) channel->volume = 0; } else if (channel->retrig < 0x40) { channel->volume -= 4; if (channel->volume > 64) channel->volume = 0; } else if (channel->retrig < 0x50) { channel->volume -= 8; if (channel->volume > 64) channel->volume = 0; } else if (channel->retrig < 0x60) { channel->volume -= 16; if (channel->volume > 64) channel->volume = 0; } else if (channel->retrig < 0x70) { channel->volume <<= 1; channel->volume /= 3; } else if (channel->retrig < 0x80) { channel->volume >>= 1; } else if (channel->retrig < 0x90) { } else if (channel->retrig < 0xA0) { channel->volume++; if (channel->volume > 64) channel->volume = 64; } else if (channel->retrig < 0xB0) { channel->volume += 2; if (channel->volume > 64) channel->volume = 64; } else if (channel->retrig < 0xC0) { channel->volume += 4; if (channel->volume > 64) channel->volume = 64; } else if (channel->retrig < 0xD0) { channel->volume += 8; if (channel->volume > 64) channel->volume = 64; } else if (channel->retrig < 0xE0) { channel->volume += 16; if (channel->volume > 64) channel->volume = 64; } else if (channel->retrig < 0xF0) { channel->volume *= 3; channel->volume >>= 1; if (channel->volume > 64) channel->volume = 64; } else { channel->volume <<= 1; if (channel->volume > 64) channel->volume = 64; } if (channel->playing) { it_playing_reset_resamplers(channel->playing, 0); channel->playing->declick_stage = 0; } else if (sigrenderer->sigdata->flags & IT_WAS_AN_XM) it_retrigger_note(sigrenderer, channel); channel->retrig_tick = channel->retrig & 0x0F; } } } static void update_smooth_effects_playing(IT_PLAYING *playing) { playing->vibrato_time += playing->vibrato_n * (playing->vibrato_speed << 2); playing->tremolo_time += playing->tremolo_speed << 2; playing->panbrello_time += playing->panbrello_speed; if (playing->panbrello_waveform == 3) playing->panbrello_random = (rand() % 129) - 64; } static void update_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) { update_smooth_effects_playing(playing); } } for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { IT_PLAYING *playing = sigrenderer->playing[i]; if (playing) { update_smooth_effects_playing(playing); } } } static const unsigned char pt_tab_invloop[16] = { 0x00, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0D, 0x0F, 0x13, 0x16, 0x1A, 0x20, 0x2B, 0x40, 0x80}; static void update_invert_loop(IT_CHANNEL *channel, IT_SAMPLE *sample) { channel->inv_loop_delay += pt_tab_invloop[channel->inv_loop_speed]; if (channel->inv_loop_delay >= 0x80) { channel->inv_loop_delay = 0; if (sample && ((sample->flags & (IT_SAMPLE_EXISTS | IT_SAMPLE_LOOP)) == (IT_SAMPLE_EXISTS | IT_SAMPLE_LOOP)) && !(sample->flags & (IT_SAMPLE_STEREO | IT_SAMPLE_16BIT))) { if (sample->loop_end - sample->loop_start >= 4) { channel->inv_loop_offset++; if (channel->inv_loop_offset >= (sample->loop_end - sample->loop_start)) channel->inv_loop_offset = 0; ((char *)sample ->data)[sample->loop_start + channel->inv_loop_offset] ^= 0xFF; } } } } static void update_playing_effects(IT_PLAYING *playing) { IT_CHANNEL *channel = playing->channel; if (channel->channelvolslide) { playing->channel_volume = channel->channelvolume; } if (channel->okt_toneslide) { if (channel->okt_toneslide--) { playing->note += channel->toneslide; if (playing->note >= 120) { if (channel->toneslide < 0) playing->note = 0; else playing->note = 119; } } } else if (channel->ptm_toneslide) { if (--channel->toneslide_tick == 0) { channel->toneslide_tick = channel->ptm_toneslide; if (playing) { playing->note += channel->toneslide; if (playing->note >= 120) { if (channel->toneslide < 0) playing->note = 0; else playing->note = 119; } if (channel->playing == playing) { channel->note = channel->truenote = playing->note; } if (channel->toneslide_retrig) { it_playing_reset_resamplers(playing, 0); playing->declick_stage = 0; } } } } } 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) { int clip = (sigrenderer->sigdata->flags & IT_WAS_AN_S3M) ? 63 : 64; channel->volume += channel->volslide; if (channel->volume > clip) { if (channel->volslide >= 0) channel->volume = clip; else channel->volume = 0; } } if (channel->panslide) { if (sigrenderer->sigdata->flags & IT_WAS_AN_XM) { if (IT_IS_SURROUND(channel->pan)) { channel->pan = 32; channel->truepan = 32 + 128 * 64; } if (channel->panslide == -128) channel->truepan = 32; else channel->truepan = MID(32, channel->truepan + channel->panslide * 64, 32 + 255 * 64); } else { if (IT_IS_SURROUND(channel->pan)) { channel->pan = 32; } channel->pan += channel->panslide; if (channel->pan > 64) { if (channel->panslide >= 0) channel->pan = 64; else channel->pan = 0; } channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; } } if (channel->channelvolslide) { channel->channelvolume += channel->channelvolslide; if (channel->channelvolume > 64) { if (channel->channelvolslide >= 0) channel->channelvolume = 64; else channel->channelvolume = 0; } } update_tremor(channel); update_retrig(sigrenderer, channel); if (channel->inv_loop_speed) update_invert_loop(channel, playing ? playing->sample : NULL); 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_playing_effects(playing); } } for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { IT_PLAYING *playing = sigrenderer->playing[i]; if (playing) update_playing_effects(playing); } update_smooth_effects(sigrenderer); } static void it_note_off(IT_PLAYING *playing); // This function should be renamed; it doesn't do the 'Update Pattern Variables' // operation ittech.txt describes /* Returns 1 if a pattern loop is happening. */ static int update_pattern_variables(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry) { IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; if (entry->mask & IT_ENTRY_EFFECT) { switch (entry->effect) { case IT_JUMP_TO_ORDER: /* XXX jump and break in same row */ if (((sigrenderer->processrow | 0xC00) == 0xFFFE) && !(sigrenderer->processrow & 0x800)) { sigrenderer->processrow = 0xFFFE & ~0xC00; } else { sigrenderer->breakrow = 0; sigrenderer->processrow = 0xFFFE & ~0x400; } sigrenderer->processorder = entry->effectvalue - 1; break; case IT_S: { unsigned char effectvalue = entry->effectvalue; if (sigrenderer->sigdata->flags & IT_WAS_AN_S3M) { if (effectvalue == 0) effectvalue = channel->lastDKL; channel->lastDKL = effectvalue; } else { if (effectvalue == 0) effectvalue = channel->lastS; } channel->lastS = effectvalue; switch (effectvalue >> 4) { case IT_S_PATTERN_LOOP: { unsigned char v = effectvalue & 15; if (v == 0) { #ifdef BIT_ARRAY_BULLSHIT if (!channel->played_patjump) channel->played_patjump = bit_array_create(256); else { if (channel->played_patjump_order != 0xFFFE && channel->played_patjump_order != sigrenderer->order) bit_array_merge( sigrenderer->played, channel->played_patjump, channel->played_patjump_order * 256); // if (channel->played_patjump_order != // sigrenderer->order) bit_array_reset(channel->played_patjump); } channel->played_patjump_order = sigrenderer->order; #endif channel->pat_loop_row = sigrenderer->processrow; } else { if (channel->pat_loop_count == 0) { #ifdef BIT_ARRAY_BULLSHIT /* wft, uninitialized and no start marker yet... */ if (channel->played_patjump_order == 0xFFFE) { int n; bit_array_destroy(channel->played_patjump); channel->played_patjump = bit_array_create(256); for (n = channel->pat_loop_row; n <= sigrenderer->row; n++) bit_array_clear(sigrenderer->played, sigrenderer->order * 256 + n); channel->played_patjump_order = sigrenderer->order; } else if (channel->played_patjump_order == sigrenderer->order) { bit_array_set(channel->played_patjump, sigrenderer->row); bit_array_mask(sigrenderer->played, channel->played_patjump, channel->played_patjump_order * 256); // bit_array_reset(channel->played_patjump); } #endif channel->pat_loop_count = v; sigrenderer->breakrow = channel->pat_loop_row; if ((sigrenderer->sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_MOD)) == IT_WAS_AN_XM) { /* For XM files, if a loop occurs by itself, keep * breakrow set for when the pattern ends - fun bug * in FT2! */ if ((sigrenderer->processrow | 0xC00) < 0xFFFE) { /* Infinite pattern loops are possible, so we * check whether the pattern loop we're hitting * now is earlier than the last one we hit. */ if (sigrenderer->processrow < channel->pat_loop_end_row) sigrenderer->processorder = 0xFFFE; /* suspect infinite loop, so trigger loop callback */ else sigrenderer->processorder = 0xFFFF; /* don't trigger loop callback */ channel->pat_loop_end_row = sigrenderer->processrow; sigrenderer->processrow = 0xFFFF; /* special case: don't reset breakrow or pat_loop_end_row */ } } else { /* IT files do this regardless of other flow control * effects seen here. */ sigrenderer->processorder = 0xFFFF; /* special case: don't trigger loop callback */ sigrenderer->processrow = 0xFFFE; } return 1; } else if (--channel->pat_loop_count) { #ifdef BIT_ARRAY_BULLSHIT if (channel->played_patjump_order == sigrenderer->order) { bit_array_set(channel->played_patjump, sigrenderer->row); bit_array_mask(sigrenderer->played, channel->played_patjump, channel->played_patjump_order * 256); // bit_array_reset(channel->played_patjump); } #endif sigrenderer->breakrow = channel->pat_loop_row; if ((sigrenderer->sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_MOD)) == IT_WAS_AN_XM) { /* For XM files, if a loop occurs by itself, keep * breakrow set for when the pattern ends - fun bug * in FT2! */ if ((sigrenderer->processrow | 0xC00) < 0xFFFE) { /* Infinite pattern loops are possible, so we * check whether the pattern loop we're hitting * now is earlier than the last one we hit. */ if (sigrenderer->processrow < channel->pat_loop_end_row) sigrenderer->processorder = 0xFFFE; /* suspect infinite loop, so trigger loop callback */ else sigrenderer->processorder = 0xFFFF; /* don't trigger loop callback */ channel->pat_loop_end_row = sigrenderer->processrow; sigrenderer->processrow = 0xFFFF; /* special case: don't reset breakrow or pat_loop_end_row */ } } else { /* IT files do this regardless of other flow control * effects seen here. */ sigrenderer->processorder = 0xFFFF; /* special case: don't trigger loop callback */ sigrenderer->processrow = 0xFFFE; } return 1; } else if ((sigrenderer->sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_MOD)) == IT_WAS_AN_XM) { channel->pat_loop_end_row = 0; // TODO /* Findings: - If a pattern loop completes successfully, and then the pattern terminates, then the next pattern will start on the row corresponding to the E60. - If a pattern loop doesn't do any loops, and then the pattern terminates, then the next pattern will start on the first row. - If a break appears to the left of the pattern loop, it jumps into the relevant position in the next pattern, and that's it. - If a break appears to the right of the pattern loop, it jumps to the start of the next pattern, and that's it. - If we jump, then effect a loop using an old E60, and then the pattern ends, the next pattern starts on the row corresponding to the E60. - Theory: breakrow is not cleared when it's a pattern loop effect! */ if ((sigrenderer->processrow | 0xC00) < 0xFFFE) // I have no idea if this is correct or not // - FT2 is so weird :( sigrenderer->breakrow = channel->pat_loop_row; /* emulate bug in FT2 */ } else channel->pat_loop_row = sigrenderer->processrow + 1; #ifdef BIT_ARRAY_BULLSHIT /*channel->played_patjump_order |= 0x8000;*/ if (channel->played_patjump_order == sigrenderer->order) { bit_array_destroy(channel->played_patjump); channel->played_patjump = 0; channel->played_patjump_order = 0xFFFE; } bit_array_clear(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row); #endif } } break; case IT_S_PATTERN_DELAY: sigrenderer->rowcount = 1 + (effectvalue & 15); break; } } } } return 0; } /* This function guarantees that channel->sample will always be valid if it * is nonzero. In other words, to check if it is valid, simply check if it is * nonzero. */ static void instrument_to_sample(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) { if (sigdata->flags & IT_USE_INSTRUMENTS) { if (channel->instrument >= 1 && channel->instrument <= sigdata->n_instruments) { if (channel->note < 120) { channel->sample = sigdata->instrument[channel->instrument - 1] .map_sample[channel->note]; channel->truenote = sigdata->instrument[channel->instrument - 1] .map_note[channel->note]; } else channel->sample = 0; } else channel->sample = 0; } else { channel->sample = channel->instrument; channel->truenote = channel->note; } if (!(channel->sample >= 1 && channel->sample <= sigdata->n_samples && (sigdata->sample[channel->sample - 1].flags & IT_SAMPLE_EXISTS) && sigdata->sample[channel->sample - 1].C5_speed)) channel->sample = 0; } static void fix_sample_looping(IT_PLAYING *playing) { if ((playing->sample->flags & (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP)) == (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP)) { if (playing->resampler.dir < 0) { playing->resampler.pos = (playing->sample->sus_loop_end << 1) - 1 - playing->resampler.pos; playing->resampler.subpos ^= 65535; playing->resampler.dir = 1; } playing->resampler.pos += playing->time_lost; // XXX what playing->time_lost = 0; } } static void it_compatible_gxx_retrigger(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) { int flags = 0; if (channel->sample) { if (sigdata->flags & IT_USE_INSTRUMENTS) { if (!(channel->playing->flags & IT_PLAYING_SUSTAINOFF)) { if (channel->playing->env_instrument->volume_envelope.flags & IT_ENVELOPE_CARRY) flags |= 1; if (channel->playing->env_instrument->pan_envelope.flags & IT_ENVELOPE_CARRY) flags |= 2; if (channel->playing->env_instrument->pitch_envelope.flags & IT_ENVELOPE_CARRY) flags |= 4; } } } if (!(flags & 1)) { channel->playing->volume_envelope.next_node = 0; channel->playing->volume_envelope.tick = 0; } if (!(flags & 2)) { channel->playing->pan_envelope.next_node = 0; channel->playing->pan_envelope.tick = 0; } if (!(flags & 4)) { channel->playing->pitch_envelope.next_node = 0; channel->playing->pitch_envelope.tick = 0; } channel->playing->fadeoutcount = 1024; // Should we remove IT_PLAYING_BACKGROUND? Test with sample with sustain // loop... channel->playing->flags &= ~(IT_PLAYING_BACKGROUND | IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING | IT_PLAYING_DEAD); it_playing_update_resamplers(channel->playing); if (!flags && channel->sample) if (sigdata->flags & IT_USE_INSTRUMENTS) channel->playing->env_instrument = &sigdata->instrument[channel->instrument - 1]; } static void it_note_off(IT_PLAYING *playing) { if (playing) { playing->enabled_envelopes |= IT_ENV_VOLUME; playing->flags |= IT_PLAYING_BACKGROUND | IT_PLAYING_SUSTAINOFF; fix_sample_looping(playing); it_playing_update_resamplers(playing); if (playing->instrument) if ((playing->instrument->volume_envelope.flags & (IT_ENVELOPE_ON | IT_ENVELOPE_LOOP_ON)) != IT_ENVELOPE_ON) playing->flags |= IT_PLAYING_FADING; } } static void xm_note_off(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) { if (channel->playing) { if (!channel->instrument || channel->instrument > sigdata->n_instruments || !(sigdata->instrument[channel->instrument - 1] .volume_envelope.flags & IT_ENVELOPE_ON)) // if (!(entry->mask & IT_ENTRY_INSTRUMENT)) // dunno what that was there for ... channel->volume = 0; channel->playing->flags |= IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING; it_playing_update_resamplers(channel->playing); } } static void recalculate_it_envelope_node(IT_PLAYING_ENVELOPE *pe, IT_ENVELOPE *e) { int envpos = pe->tick; unsigned int pt = e->n_nodes - 1; unsigned int i; for (i = 0; i < (unsigned int)(e->n_nodes - 1); ++i) { if (envpos <= e->node_t[i]) { pt = i; break; } } pe->next_node = pt; } static void recalculate_it_envelope_nodes(IT_PLAYING *playing) { recalculate_it_envelope_node(&playing->volume_envelope, &playing->env_instrument->volume_envelope); recalculate_it_envelope_node(&playing->pan_envelope, &playing->env_instrument->pitch_envelope); recalculate_it_envelope_node(&playing->pitch_envelope, &playing->env_instrument->pitch_envelope); } static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel) { int vol_env_tick = 0; int pan_env_tick = 0; int pitch_env_tick = 0; DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; unsigned char nna = ~0; int i, envelopes_copied = 0; if (channel->playing) { if (channel->note == IT_NOTE_CUT) nna = NNA_NOTE_CUT; else if (channel->note == IT_NOTE_OFF) nna = NNA_NOTE_OFF; else if (channel->note > 120) nna = NNA_NOTE_FADE; else if (!channel->playing->instrument || (channel->playing->flags & IT_PLAYING_DEAD)) nna = NNA_NOTE_CUT; else if (channel->new_note_action != 0xFF) { nna = channel->new_note_action; } else nna = channel->playing->instrument->new_note_action; if (!(channel->playing->flags & IT_PLAYING_SUSTAINOFF)) { if (nna != NNA_NOTE_CUT) vol_env_tick = channel->playing->volume_envelope.tick; pan_env_tick = channel->playing->pan_envelope.tick; pitch_env_tick = channel->playing->pitch_envelope.tick; envelopes_copied = 1; } switch (nna) { case NNA_NOTE_CUT: channel->playing->declick_stage = 3; break; case NNA_NOTE_OFF: it_note_off(channel->playing); break; case NNA_NOTE_FADE: channel->playing->flags |= IT_PLAYING_BACKGROUND | IT_PLAYING_FADING; break; } } channel->new_note_action = 0xFF; if (channel->sample == 0 || channel->note > 120) return; channel->destnote = IT_NOTE_OFF; if (channel->playing) { for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (!sigrenderer->playing[i]) { sigrenderer->playing[i] = channel->playing; channel->playing = NULL; break; } } if (sigrenderer->sigdata->flags & IT_USE_INSTRUMENTS) { for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { IT_PLAYING *playing = sigrenderer->playing[i]; if (playing && playing->channel == channel && playing->instrument->dup_check_type) { int match = 1; switch (playing->instrument->dup_check_type) { case DCT_NOTE: match = (channel->truenote == playing->note); case DCT_SAMPLE: match = match && (channel->sample == playing->sampnum); case DCT_INSTRUMENT: match = match && (channel->instrument == playing->instnum); break; } if (match) { switch (playing->instrument->dup_check_action) { case DCA_NOTE_CUT: playing->declick_stage = 3; if (channel->playing == playing) channel->playing = NULL; break; case DCA_NOTE_OFF: if (!(playing->flags & IT_PLAYING_SUSTAINOFF)) it_note_off(playing); break; case DCA_NOTE_FADE: playing->flags |= IT_PLAYING_BACKGROUND | IT_PLAYING_FADING; break; } } } } } /** WARNING - come up with some more heuristics for replacing old notes */ #if 0 if (channel->playing) { for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (sigrenderer->playing[i]->flags & IT_PLAYING_BACKGROUND) { write_seqtime(); sequence_c(SEQUENCE_STOP_SIGNAL); sequence_c(i); channel->VChannel = &module->VChannel[i]; break; } } } #endif } if (channel->playing) free_playing(channel->playing); channel->playing = new_playing(); if (!channel->playing) return; if (!envelopes_copied && sigdata->flags & IT_USE_INSTRUMENTS) { for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { IT_PLAYING *playing = sigrenderer->playing[i]; if (!playing || playing->channel != channel) continue; if (playing->flags & IT_PLAYING_SUSTAINOFF) continue; if (nna != NNA_NOTE_CUT) vol_env_tick = playing->volume_envelope.tick; pan_env_tick = playing->pan_envelope.tick; pitch_env_tick = playing->pitch_envelope.tick; envelopes_copied = 1; break; } } channel->playing->flags = 0; channel->playing->resampling_quality = sigrenderer->resampling_quality; channel->playing->channel = channel; channel->playing->sample = &sigdata->sample[channel->sample - 1]; if (sigdata->flags & IT_USE_INSTRUMENTS) channel->playing->instrument = &sigdata->instrument[channel->instrument - 1]; else channel->playing->instrument = NULL; channel->playing->env_instrument = channel->playing->instrument; channel->playing->sampnum = channel->sample; channel->playing->instnum = channel->instrument; channel->playing->declick_stage = 0; channel->playing->channel_volume = channel->channelvolume; channel->playing->note = channel->truenote; channel->playing->enabled_envelopes = 0; channel->playing->volume_offset = 0; channel->playing->panning_offset = 0; // channel->playing->output = channel->output; if (sigdata->flags & IT_USE_INSTRUMENTS) { IT_PLAYING *playing = channel->playing; IT_INSTRUMENT *instrument = playing->instrument; if (instrument->volume_envelope.flags & IT_ENVELOPE_ON) playing->enabled_envelopes |= IT_ENV_VOLUME; if (instrument->pan_envelope.flags & IT_ENVELOPE_ON) playing->enabled_envelopes |= IT_ENV_PANNING; if (instrument->pitch_envelope.flags & IT_ENVELOPE_ON) playing->enabled_envelopes |= IT_ENV_PITCH; if (instrument->random_volume) playing->volume_offset = (rand() % (instrument->random_volume * 2 + 1)) - instrument->random_volume; if (instrument->random_pan) playing->panning_offset = (rand() % (instrument->random_pan * 2 + 1)) - instrument->random_pan; // if (instrument->output) playing->output = instrument->output; } channel->playing->filter_cutoff = 127; channel->playing->filter_resonance = 0; channel->playing->true_filter_cutoff = 127 << 8; channel->playing->true_filter_resonance = 0; channel->playing->vibrato_speed = 0; channel->playing->vibrato_depth = 0; channel->playing->vibrato_n = 0; channel->playing->vibrato_time = 0; channel->playing->vibrato_waveform = channel->vibrato_waveform; channel->playing->tremolo_speed = 0; channel->playing->tremolo_depth = 0; channel->playing->tremolo_time = 0; channel->playing->tremolo_waveform = channel->tremolo_waveform; channel->playing->panbrello_speed = 0; channel->playing->panbrello_depth = 0; channel->playing->panbrello_time = 0; channel->playing->panbrello_waveform = channel->panbrello_waveform; channel->playing->panbrello_random = 0; channel->playing->sample_vibrato_time = 0; channel->playing->sample_vibrato_waveform = channel->playing->sample->vibrato_waveform; channel->playing->sample_vibrato_depth = 0; channel->playing->slide = 0; channel->playing->finetune = channel->playing->sample->finetune; if (sigdata->flags & IT_USE_INSTRUMENTS) { if (envelopes_copied && channel->playing->env_instrument->volume_envelope.flags & IT_ENVELOPE_CARRY) { channel->playing->volume_envelope.tick = vol_env_tick; } else { channel->playing->volume_envelope.tick = 0; } if (envelopes_copied && channel->playing->env_instrument->pan_envelope.flags & IT_ENVELOPE_CARRY) { channel->playing->pan_envelope.tick = pan_env_tick; } else { channel->playing->pan_envelope.tick = 0; } if (envelopes_copied && channel->playing->env_instrument->pitch_envelope.flags & IT_ENVELOPE_CARRY) { channel->playing->pitch_envelope.tick = pitch_env_tick; } else { channel->playing->pitch_envelope.tick = 0; } recalculate_it_envelope_nodes(channel->playing); } channel->playing->fadeoutcount = 1024; it_reset_filter_state(&channel->playing->filter_state[0]); it_reset_filter_state(&channel->playing->filter_state[1]); it_playing_reset_resamplers(channel->playing, 0); /** WARNING - is everything initialised? */ } static void get_default_volpan(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) { if (channel->sample == 0) return; channel->volume = sigdata->sample[channel->sample - 1].default_volume; if (sigdata->flags & IT_WAS_AN_XM) { if (!(sigdata->flags & IT_WAS_A_MOD)) channel->truepan = 32 + sigdata->sample[channel->sample - 1].default_pan * 64; return; } { int pan = sigdata->sample[channel->sample - 1].default_pan; if (pan >= 128 && pan <= 192) { channel->pan = pan - 128; return; } } if (sigdata->flags & IT_USE_INSTRUMENTS) { IT_INSTRUMENT *instrument = &sigdata->instrument[channel->instrument - 1]; if (instrument->default_pan <= 64) channel->pan = instrument->default_pan; if (instrument->filter_cutoff >= 128) channel->filter_cutoff = instrument->filter_cutoff - 128; if (instrument->filter_resonance >= 128) channel->filter_resonance = instrument->filter_resonance - 128; } } static void get_true_pan(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) { channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; if (channel->sample && !IT_IS_SURROUND_SHIFTED(channel->truepan) && (sigdata->flags & IT_USE_INSTRUMENTS)) { IT_INSTRUMENT *instrument = &sigdata->instrument[channel->instrument - 1]; int truepan = channel->truepan; truepan += (channel->note - instrument->pp_centre) * instrument->pp_separation << (IT_ENVELOPE_SHIFT - 3); channel->truepan = (unsigned short)MID(0, truepan, 64 << IT_ENVELOPE_SHIFT); } } static void post_process_it_volpan(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry) { IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; if (entry->mask & IT_ENTRY_VOLPAN) { if (entry->volpan <= 84) { /* Volume */ /* Fine volume slide up */ /* Fine volume slide down */ } else if (entry->volpan <= 94) { /* Volume slide up */ unsigned char v = entry->volpan - 85; if (v == 0) v = channel->lastvolslide; channel->lastvolslide = v; /* = effect Dx0 where x == entry->volpan - 85 */ channel->volslide += v; } else if (entry->volpan <= 104) { /* Volume slide down */ unsigned char v = entry->volpan - 95; if (v == 0) v = channel->lastvolslide; channel->lastvolslide = v; /* = effect D0x where x == entry->volpan - 95 */ channel->volslide -= v; } else if (entry->volpan <= 114) { /* Portamento down */ unsigned char v = (entry->volpan - 105) << 2; if (v == 0) v = channel->lastEF; channel->lastEF = v; channel->portamento -= v << 4; } else if (entry->volpan <= 124) { /* Portamento up */ unsigned char v = (entry->volpan - 115) << 2; if (v == 0) v = channel->lastEF; channel->lastEF = v; channel->portamento += v << 4; } else if (entry->volpan <= 202) { /* Pan */ /* Tone Portamento */ } else if (entry->volpan <= 212) { /* Vibrato */ /* This is unaffected by IT_OLD_EFFECTS. However, if v == 0, then * any doubling of depth that happened before (with Hxy in the * effect column) will be preserved. */ unsigned char v = entry->volpan - 203; if (v == 0) v = channel->lastHdepth; else { v <<= 2; channel->lastHdepth = v; } if (channel->playing) { channel->playing->vibrato_speed = channel->lastHspeed; channel->playing->vibrato_depth = v; channel->playing->vibrato_n++; } } } } static void it_send_midi(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel, unsigned char midi_byte) { if (sigrenderer->callbacks->midi) if ((*sigrenderer->callbacks->midi)( sigrenderer->callbacks->midi_data, (int)(channel - sigrenderer->channel), midi_byte)) return; switch (channel->midi_state) { case 4: /* Ready to receive resonance parameter */ if (midi_byte < 0x80) channel->filter_resonance = midi_byte; channel->midi_state = 0; break; case 3: /* Ready to receive cutoff parameter */ if (midi_byte < 0x80) channel->filter_cutoff = midi_byte; channel->midi_state = 0; break; case 2: /* Ready for byte specifying which parameter will follow */ if (midi_byte == 0) /* Cutoff */ channel->midi_state = 3; else if (midi_byte == 1) /* Resonance */ channel->midi_state = 4; else channel->midi_state = 0; break; default: /* Counting initial F0 bytes */ switch (midi_byte) { case 0xF0: channel->midi_state++; break; case 0xFA: case 0xFC: case 0xFF: /* Reset filter parameters for all channels */ { int i; for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { sigrenderer->channel[i].filter_cutoff = 127; sigrenderer->channel[i].filter_resonance = 0; //// should we be resetting channel[i].playing->filter_* /// here? } } /* Fall through */ default: channel->midi_state = 0; break; } } } static void xm_envelope_calculate_value(IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe) { if (pe->next_node <= 0) pe->value = envelope->node_y[0] << IT_ENVELOPE_SHIFT; else if (pe->next_node >= envelope->n_nodes) pe->value = envelope->node_y[envelope->n_nodes - 1] << IT_ENVELOPE_SHIFT; else { int ys = envelope->node_y[pe->next_node - 1] << IT_ENVELOPE_SHIFT; int ts = envelope->node_t[pe->next_node - 1]; int te = envelope->node_t[pe->next_node]; if (ts == te) pe->value = ys; else { int ye = envelope->node_y[pe->next_node] << IT_ENVELOPE_SHIFT; int t = pe->tick; pe->value = ys + (ye - ys) * (t - ts) / (te - ts); } } } extern const char xm_convert_vibrato[]; const char mod_convert_vibrato[] = { IT_VIBRATO_SINE, IT_VIBRATO_RAMP_UP, /* this will be inverted by IT_OLD_EFFECTS */ IT_VIBRATO_XM_SQUARE, IT_VIBRATO_XM_SQUARE}; /* 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_PLAYING *playing; int i; IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; if (entry->mask & IT_ENTRY_EFFECT) { switch (entry->effect) { /* Notes about effects (as compared to other module formats) C This is now in *HEX*. (Used to be in decimal in ST3) E/F/G/H/U You need to check whether the song uses Amiga/Linear slides. H/U Vibrato in Impulse Tracker is two times finer than in any other tracker and is updated EVERY tick. If "Old Effects" is *ON*, then the vibrato is played in the normal manner (every non-row tick and normal depth) E/F/G These commands ALL share the same memory. Oxx Offsets to samples are to the 'xx00th' SAMPLE. (ie. for 16 bit samples, the offset is xx00h*2) Oxx past the sample end will be ignored, unless "Old Effects" is ON, in which case the Oxx will play from the end of the sample. Yxy This uses a table 4 times larger (hence 4 times slower) than vibrato or tremelo. If the waveform is set to random, then the 'speed' part of the command is interpreted as a delay. */ case IT_SET_SPEED: if (entry->effectvalue) { /*if (entry->effectvalue == 255) if (sigrenderer->callbacks->xm_speed_zero && (*sigrenderer->callbacks->xm_speed_zero)(sigrenderer->callbacks->xm_speed_zero_data)) return 1;*/ if (sigdata->flags & IT_WAS_AN_STM) { int n = entry->effectvalue; if (n >= 32) { sigrenderer->tick = sigrenderer->speed = n; } } else { sigrenderer->tick = sigrenderer->speed = entry->effectvalue; } } else if ((sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_MOD)) == IT_WAS_AN_XM) { #ifdef BIT_ARRAY_BULLSHIT bit_array_set(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row); #endif sigrenderer->speed = 0; #ifdef BIT_ARRAY_BULLSHIT sigrenderer->looped = 1; #endif if (sigrenderer->callbacks->xm_speed_zero && (*sigrenderer->callbacks->xm_speed_zero)( sigrenderer->callbacks->xm_speed_zero_data)) return 1; } break; case IT_BREAK_TO_ROW: if (ignore_cxx) break; sigrenderer->breakrow = entry->effectvalue; /* XXX jump and break on the same row */ if (((sigrenderer->processrow | 0xC00) == 0xFFFE) && !(sigrenderer->processrow & 0x400)) { sigrenderer->processrow = 0xFFFE & ~0xC00; } else { sigrenderer->processorder = sigrenderer->order; sigrenderer->processrow = 0xFFFE & ~0x800; } break; case IT_VOLSLIDE_VIBRATO: for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (i < 0) playing = channel->playing; else { playing = sigrenderer->playing[i]; if (!playing || playing->channel != channel) continue; } if (playing) { playing->vibrato_speed = channel->lastHspeed; playing->vibrato_depth = channel->lastHdepth; playing->vibrato_n++; } } /* Fall through and process volume slide. */ case IT_VOLUME_SLIDE: case IT_VOLSLIDE_TONEPORTA: /* The tone portamento component is handled elsewhere. */ { unsigned char v = entry->effectvalue; if (!(sigdata->flags & IT_WAS_A_MOD)) { if (v == 0) v = channel->lastDKL; channel->lastDKL = v; } if (!(sigdata->flags & IT_WAS_AN_XM)) { int clip = (sigdata->flags & IT_WAS_AN_S3M) ? 63 : 64; if ((v & 0x0F) == 0x0F) { if (!(v & 0xF0)) { channel->volslide = -15; channel->volume -= 15; if (channel->volume > clip) channel->volume = 0; } else { channel->volume += v >> 4; if (channel->volume > clip) channel->volume = clip; } } else if ((v & 0xF0) == 0xF0) { if (!(v & 0x0F)) { channel->volslide = 15; channel->volume += 15; if (channel->volume > clip) channel->volume = clip; } else { channel->volume -= v & 15; if (channel->volume > clip) channel->volume = 0; } } else if (!(v & 0x0F)) { channel->volslide = v >> 4; } else { channel->volslide = -(v & 15); } } else { if ((v & 0x0F) == 0) { /* Dx0 */ channel->volslide = v >> 4; } else if ((v & 0xF0) == 0) { /* D0x */ channel->volslide = -v; } else if ((v & 0x0F) == 0x0F) { /* DxF */ channel->volume += v >> 4; if (channel->volume > 64) channel->volume = 64; } else if ((v & 0xF0) == 0xF0) { /* DFx */ channel->volume -= v & 15; if (channel->volume > 64) channel->volume = 0; } } } break; case IT_XM_FINE_VOLSLIDE_DOWN: { unsigned char v = entry->effectvalue; if (v == 0) v = channel->xm_lastEB; channel->xm_lastEB = v; channel->volume -= v; if (channel->volume > 64) channel->volume = 0; } break; case IT_XM_FINE_VOLSLIDE_UP: { unsigned char v = entry->effectvalue; if (v == 0) v = channel->xm_lastEA; channel->xm_lastEA = v; channel->volume += v; if (channel->volume > 64) channel->volume = 64; } break; case IT_PORTAMENTO_DOWN: { unsigned char v = entry->effectvalue; if (sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_669)) { if (!(sigdata->flags & IT_WAS_A_MOD)) { if (v == 0xF0) v |= channel->xm_lastE2; else if (v >= 0xF0) channel->xm_lastE2 = v & 15; else if (v == 0xE0) v |= channel->xm_lastX2; else channel->xm_lastX2 = v & 15; } } else if (sigdata->flags & IT_WAS_AN_S3M) { if (v == 0) v = channel->lastDKL; channel->lastDKL = v; } else { if (v == 0) v = channel->lastEF; channel->lastEF = v; } for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (i < 0) playing = channel->playing; else { playing = sigrenderer->playing[i]; if (!playing || playing->channel != channel) continue; } if (playing) { if ((v & 0xF0) == 0xF0) playing->slide -= (v & 15) << 4; else if ((v & 0xF0) == 0xE0) playing->slide -= (v & 15) << 2; else if (i < 0 && sigdata->flags & IT_WAS_A_669) channel->portamento -= v << 3; else if (i < 0) channel->portamento -= v << 4; } } } break; case IT_PORTAMENTO_UP: { unsigned char v = entry->effectvalue; if (sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_669)) { if (!(sigdata->flags & IT_WAS_A_MOD)) { if (v == 0xF0) v |= channel->xm_lastE1; else if (v >= 0xF0) channel->xm_lastE1 = v & 15; else if (v == 0xE0) v |= channel->xm_lastX1; else channel->xm_lastX1 = v & 15; } } else if (sigdata->flags & IT_WAS_AN_S3M) { if (v == 0) v = channel->lastDKL; channel->lastDKL = v; } else { if (v == 0) v = channel->lastEF; channel->lastEF = v; } for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (i < 0) playing = channel->playing; else { playing = sigrenderer->playing[i]; if (!playing || playing->channel != channel) continue; } if (playing) { if ((v & 0xF0) == 0xF0) playing->slide += (v & 15) << 4; else if ((v & 0xF0) == 0xE0) playing->slide += (v & 15) << 2; else if (i < 0 && sigdata->flags & IT_WAS_A_669) channel->portamento += v << 3; else if (i < 0) channel->portamento += v << 4; } } } break; case IT_XM_PORTAMENTO_DOWN: { unsigned char v = entry->effectvalue; if (!(sigdata->flags & IT_WAS_A_MOD)) { if (v == 0) v = channel->lastJ; channel->lastJ = v; } if (channel->playing) channel->portamento -= v << 4; } break; case IT_XM_PORTAMENTO_UP: { unsigned char v = entry->effectvalue; if (!(sigdata->flags & IT_WAS_A_MOD)) { if (v == 0) v = channel->lastEF; channel->lastEF = v; } if (channel->playing) channel->portamento += v << 4; } break; case IT_XM_KEY_OFF: channel->key_off_count = entry->effectvalue; if (!channel->key_off_count) xm_note_off(sigdata, channel); break; case IT_VIBRATO: { if (entry->effectvalue || !(sigdata->flags & IT_WAS_A_669)) { unsigned char speed = entry->effectvalue >> 4; unsigned char depth = entry->effectvalue & 15; if (speed == 0) speed = channel->lastHspeed; channel->lastHspeed = speed; if (depth == 0) depth = channel->lastHdepth; else { if (sigdata->flags & IT_OLD_EFFECTS && !(sigdata->flags & IT_WAS_A_MOD)) depth <<= 3; else depth <<= 2; channel->lastHdepth = depth; } for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (i < 0) playing = channel->playing; else { playing = sigrenderer->playing[i]; if (!playing || playing->channel != channel) continue; } if (playing) { playing->vibrato_speed = speed; playing->vibrato_depth = depth; playing->vibrato_n++; } } } } break; case IT_TREMOR: { unsigned char v = entry->effectvalue; if (v == 0) { if (sigdata->flags & IT_WAS_AN_S3M) v = channel->lastDKL; else v = channel->lastI; } else if (!(sigdata->flags & IT_OLD_EFFECTS)) { if (v & 0xF0) v -= 0x10; if (v & 0x0F) v -= 0x01; } if (sigdata->flags & IT_WAS_AN_S3M) channel->lastDKL = v; else channel->lastI = v; channel->tremor_time |= 128; } update_tremor(channel); break; case IT_ARPEGGIO: { unsigned char v = entry->effectvalue; /* XM files have no memory for arpeggio (000 = no effect) * and we use lastJ for portamento down instead. */ if (!(sigdata->flags & IT_WAS_AN_XM)) { if (sigdata->flags & IT_WAS_AN_S3M) { if (v == 0) v = channel->lastDKL; channel->lastDKL = v; } else { if (v == 0) v = channel->lastJ; channel->lastJ = v; } } channel->arpeggio_offsets[0] = 0; channel->arpeggio_offsets[1] = (v & 0xF0) >> 4; channel->arpeggio_offsets[2] = (v & 0x0F); channel->arpeggio_table = (const unsigned char *)(((sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_MOD)) == IT_WAS_AN_XM) ? &arpeggio_xm : &arpeggio_mod); } break; case IT_SET_CHANNEL_VOLUME: if (sigdata->flags & IT_WAS_AN_XM) channel->volume = MIN(entry->effectvalue, 64); else if (entry->effectvalue <= 64) channel->channelvolume = entry->effectvalue; #ifdef VOLUME_OUT_OF_RANGE_SETS_MAXIMUM else channel->channelvolume = 64; #endif if (channel->playing) channel->playing->channel_volume = channel->channelvolume; break; case IT_CHANNEL_VOLUME_SLIDE: { unsigned char v = entry->effectvalue; if (v == 0) v = channel->lastN; channel->lastN = v; if ((v & 0x0F) == 0) { /* Nx0 */ channel->channelvolslide = v >> 4; } else if ((v & 0xF0) == 0) { /* N0x */ channel->channelvolslide = -v; } else { if ((v & 0x0F) == 0x0F) { /* NxF */ channel->channelvolume += v >> 4; if (channel->channelvolume > 64) channel->channelvolume = 64; } else if ((v & 0xF0) == 0xF0) { /* NFx */ channel->channelvolume -= v & 15; if (channel->channelvolume > 64) channel->channelvolume = 0; } else break; if (channel->playing) channel->playing->channel_volume = channel->channelvolume; } } break; case IT_SET_SAMPLE_OFFSET: { unsigned char v = entry->effectvalue; /*if (sigdata->flags & IT_WAS_A_MOD) { if (v == 0) break; } else*/ { if (v == 0) v = channel->lastO; channel->lastO = v; } /* Note: we set the offset even if tone portamento is * specified. Impulse Tracker does the same. */ if (entry->mask & IT_ENTRY_NOTE) { if (channel->playing) { int offset = ((int)channel->high_offset << 16) | ((int)v << 8); IT_PLAYING *playing = channel->playing; IT_SAMPLE *sample = playing->sample; int end; if ((sample->flags & IT_SAMPLE_SUS_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) end = (int)sample->sus_loop_end; else if (sample->flags & IT_SAMPLE_LOOP) end = (int)sample->loop_end; else { end = (int)sample->length; if (sigdata->flags & IT_WAS_PROCESSED && end > 64) // XXX bah damn LPC and edge case modules end -= 64; } if ((sigdata->flags & IT_WAS_A_PTM) && (sample->flags & IT_SAMPLE_16BIT)) offset >>= 1; if (offset < end) { it_playing_reset_resamplers(playing, offset); playing->declick_stage = 0; } else if (sigdata->flags & IT_OLD_EFFECTS) { it_playing_reset_resamplers(playing, end); playing->declick_stage = 0; } } } } break; case IT_PANNING_SLIDE: /** JULIEN: guess what? the docs are wrong! (how unusual ;) * Pxy seems to memorize its previous value... and there * might be other mistakes like that... (sigh!) */ /** ENTHEH: umm... but... the docs say that Pxy memorises its * value... don't they? :o */ { unsigned char v = entry->effectvalue; int p = channel->truepan; if (sigdata->flags & IT_WAS_AN_XM) { if (IT_IS_SURROUND(channel->pan)) { channel->pan = 32; p = 32 + 128 * 64; } p >>= 6; } else { if (IT_IS_SURROUND(channel->pan)) p = 32 << 8; p = (p + 128) >> 8; channel->pan = p; } if (v == 0) v = channel->lastP; channel->lastP = v; if ((v & 0x0F) == 0) { /* Px0 */ channel->panslide = -(v >> 4); } else if ((v & 0xF0) == 0) { /* P0x */ channel->panslide = v; } else if ((v & 0x0F) == 0x0F) { /* PxF */ p -= v >> 4; } else if ((v & 0xF0) == 0xF0) { /* PFx */ p += v & 15; } if (sigdata->flags & IT_WAS_AN_XM) channel->truepan = 32 + MID(0, p, 255) * 64; else { if (p < 0) p = 0; else if (p > 64) p = 64; channel->pan = p; channel->truepan = p << 8; } } break; case IT_RETRIGGER_NOTE: { unsigned char v = entry->effectvalue; if (sigdata->flags & IT_WAS_AN_XM) { if ((v & 0x0F) == 0) v |= channel->lastQ & 0x0F; if ((v & 0xF0) == 0) v |= channel->lastQ & 0xF0; channel->lastQ = v; } else if (sigdata->flags & IT_WAS_AN_S3M) { if (v == 0) v = channel->lastDKL; channel->lastDKL = v; } else { if (v == 0) v = channel->lastQ; channel->lastQ = v; } if ((v & 0x0F) == 0) v |= 0x01; channel->retrig = v; if (entry->mask & IT_ENTRY_NOTE) { channel->retrig_tick = v & 0x0F; /* Emulate a bug */ if (sigdata->flags & IT_WAS_AN_XM) update_retrig(sigrenderer, channel); } else update_retrig(sigrenderer, channel); } break; case IT_XM_RETRIGGER_NOTE: channel->retrig_tick = channel->xm_retrig = entry->effectvalue; if (entry->effectvalue == 0) if (channel->playing) { it_playing_reset_resamplers(channel->playing, 0); channel->playing->declick_stage = 0; } break; case IT_TREMOLO: { unsigned char speed, depth; if (sigdata->flags & IT_WAS_AN_S3M) { unsigned char v = entry->effectvalue; if (v == 0) v = channel->lastDKL; channel->lastDKL = v; speed = v >> 4; depth = v & 15; } else { speed = entry->effectvalue >> 4; depth = entry->effectvalue & 15; if (speed == 0) speed = channel->lastRspeed; channel->lastRspeed = speed; if (depth == 0) depth = channel->lastRdepth; channel->lastRdepth = depth; } for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (i < 0) playing = channel->playing; else { playing = sigrenderer->playing[i]; if (!playing || playing->channel != channel) continue; } if (playing) { playing->tremolo_speed = speed; playing->tremolo_depth = depth; } } } break; case IT_S: { /* channel->lastS was set in update_pattern_variables(). */ unsigned char effectvalue = channel->lastS; switch (effectvalue >> 4) { // case IT_S_SET_FILTER: /* Waveforms for commands S3x, S4x and S5x: * 0: Sine wave * 1: Ramp down * 2: Square wave * 3: Random wave */ case IT_S_SET_GLISSANDO_CONTROL: channel->glissando = effectvalue & 15; break; case IT_S_FINETUNE: if (channel->playing) { channel->playing->finetune = ((int)(effectvalue & 15) - 8) << 5; } break; case IT_S_SET_VIBRATO_WAVEFORM: { int waveform = effectvalue & 3; if (sigdata->flags & IT_WAS_A_MOD) waveform = mod_convert_vibrato[waveform]; else if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform]; channel->vibrato_waveform = waveform; if (channel->playing) { channel->playing->vibrato_waveform = waveform; if (!(effectvalue & 4)) channel->playing->vibrato_time = 0; } } break; case IT_S_SET_TREMOLO_WAVEFORM: { int waveform = effectvalue & 3; if (sigdata->flags & IT_WAS_A_MOD) waveform = mod_convert_vibrato[waveform]; else if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform]; channel->tremolo_waveform = waveform; if (channel->playing) { channel->playing->tremolo_waveform = waveform; if (!(effectvalue & 4)) channel->playing->tremolo_time = 0; } } break; case IT_S_SET_PANBRELLO_WAVEFORM: channel->panbrello_waveform = effectvalue & 3; if (channel->playing) { channel->playing->panbrello_waveform = effectvalue & 3; if (!(effectvalue & 4)) channel->playing->panbrello_time = 0; } break; case IT_S_FINE_PATTERN_DELAY: sigrenderer->tick += effectvalue & 15; break; #if 1 case IT_S7: { if (sigrenderer->sigdata->flags & IT_USE_INSTRUMENTS) { int i; switch (effectvalue & 15) { case 0: /* cut background notes */ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { IT_PLAYING *playing = sigrenderer->playing[i]; if (playing && channel == playing->channel) { playing->declick_stage = 3; if (channel->playing == playing) channel->playing = NULL; } } break; case 1: /* release background notes */ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { IT_PLAYING *playing = sigrenderer->playing[i]; if (playing && channel == playing->channel && !(playing->flags & IT_PLAYING_SUSTAINOFF)) { it_note_off(playing); } } break; case 2: /* fade background notes */ for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { IT_PLAYING *playing = sigrenderer->playing[i]; if (playing && channel == playing->channel) { // playing->flags &= IT_PLAYING_SUSTAINOFF; playing->flags |= IT_PLAYING_FADING; } } break; case 3: channel->new_note_action = NNA_NOTE_CUT; break; case 4: channel->new_note_action = NNA_NOTE_CONTINUE; break; case 5: channel->new_note_action = NNA_NOTE_OFF; break; case 6: channel->new_note_action = NNA_NOTE_FADE; break; case 7: if (channel->playing) channel->playing->enabled_envelopes &= ~IT_ENV_VOLUME; break; case 8: if (channel->playing) channel->playing->enabled_envelopes |= IT_ENV_VOLUME; break; case 9: if (channel->playing) channel->playing->enabled_envelopes &= ~IT_ENV_PANNING; break; case 10: if (channel->playing) channel->playing->enabled_envelopes |= IT_ENV_PANNING; break; case 11: if (channel->playing) channel->playing->enabled_envelopes &= ~IT_ENV_PITCH; break; case 12: if (channel->playing) channel->playing->enabled_envelopes |= IT_ENV_PITCH; break; } } } break; #endif case IT_S_SET_PAN: // ASSERT(!(sigdata->flags & IT_WAS_AN_XM)); channel->pan = ((effectvalue & 15) << 2) | ((effectvalue & 15) >> 2); channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; if (channel->playing) channel->playing->panbrello_depth = 0; break; case IT_S_SET_SURROUND_SOUND: if ((effectvalue & 15) == 15) { if (channel->playing && channel->playing->sample && !(channel->playing->sample->flags & (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP))) { channel->playing->flags |= IT_PLAYING_REVERSE; it_playing_reset_resamplers( channel->playing, channel->playing->sample->length - 1); } } else if ((effectvalue & 15) == 1) { channel->pan = IT_SURROUND; channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; } if (channel->playing) channel->playing->panbrello_depth = 0; break; case IT_S_SET_HIGH_OFFSET: channel->high_offset = effectvalue & 15; break; // case IT_S_PATTERN_LOOP: case IT_S_DELAYED_NOTE_CUT: channel->note_cut_count = effectvalue & 15; if (!channel->note_cut_count) { if (sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_PTM)) channel->volume = 0; else channel->note_cut_count = 1; } break; case IT_S_SET_MIDI_MACRO: if ((sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_MOD)) == (IT_WAS_AN_XM | IT_WAS_A_MOD)) { channel->inv_loop_speed = effectvalue & 15; update_invert_loop(channel, channel->playing ? channel->playing->sample : NULL); } else channel->SFmacro = effectvalue & 15; break; } } break; case IT_SET_SONG_TEMPO: { unsigned char v = entry->effectvalue; if (v == 0) v = channel->lastW; channel->lastW = v; if (v < 0x10) sigrenderer->temposlide = -v; else if (v < 0x20) sigrenderer->temposlide = v & 15; else sigrenderer->tempo = v; } break; case IT_FINE_VIBRATO: { unsigned char speed = entry->effectvalue >> 4; unsigned char depth = entry->effectvalue & 15; if (speed == 0) speed = channel->lastHspeed; channel->lastHspeed = speed; if (depth == 0) depth = channel->lastHdepth; else { if (sigdata->flags & IT_OLD_EFFECTS) depth <<= 1; channel->lastHdepth = depth; } for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (i < 0) playing = channel->playing; else { playing = sigrenderer->playing[i]; if (!playing || playing->channel != channel) continue; } if (playing) { playing->vibrato_speed = speed; playing->vibrato_depth = depth; playing->vibrato_n++; } } } break; case IT_SET_GLOBAL_VOLUME: if ((sigdata->flags & IT_WAS_AN_S3M) && (entry->effectvalue > 64)) break; if (entry->effectvalue <= 128) sigrenderer->globalvolume = entry->effectvalue; #ifdef VOLUME_OUT_OF_RANGE_SETS_MAXIMUM else sigrenderer->globalvolume = 128; #endif break; case IT_GLOBAL_VOLUME_SLIDE: { unsigned char v = entry->effectvalue; if (v == 0) v = channel->lastW; channel->lastW = v; if ((v & 0x0F) == 0) { /* Wx0 */ sigrenderer->globalvolslide = (sigdata->flags & IT_WAS_AN_XM) ? (v >> 4) * 2 : (v >> 4); } else if ((v & 0xF0) == 0) { /* W0x */ sigrenderer->globalvolslide = (sigdata->flags & IT_WAS_AN_XM) ? (-v) * 2 : (-v); } else if ((v & 0x0F) == 0x0F) { /* WxF */ sigrenderer->globalvolume += v >> 4; if (sigrenderer->globalvolume > 128) sigrenderer->globalvolume = 128; } else if ((v & 0xF0) == 0xF0) { /* WFx */ sigrenderer->globalvolume -= v & 15; if (sigrenderer->globalvolume > 128) sigrenderer->globalvolume = 0; } } break; case IT_SET_PANNING: if (sigdata->flags & IT_WAS_AN_XM) { channel->truepan = 32 + entry->effectvalue * 64; } else { if (sigdata->flags & IT_WAS_AN_S3M) channel->pan = (entry->effectvalue + 1) >> 1; else channel->pan = (entry->effectvalue + 2) >> 2; channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; } if (channel->playing) channel->playing->panbrello_depth = 0; break; case IT_PANBRELLO: { unsigned char speed = entry->effectvalue >> 4; unsigned char depth = entry->effectvalue & 15; if (speed == 0) speed = channel->lastYspeed; channel->lastYspeed = speed; if (depth == 0) depth = channel->lastYdepth; channel->lastYdepth = depth; if (channel->playing) { channel->playing->panbrello_speed = speed; channel->playing->panbrello_depth = depth; } } break; case IT_MIDI_MACRO: { const IT_MIDI *midi = sigdata->midi ? sigdata->midi : &default_midi; if (entry->effectvalue >= 0x80) { int n = midi->Zmacrolen[entry->effectvalue - 0x80]; int i; for (i = 0; i < n; i++) it_send_midi(sigrenderer, channel, midi->Zmacro[entry->effectvalue - 0x80][i]); } else { int n = midi->SFmacrolen[channel->SFmacro]; int i, j; for (i = 0, j = 1; i < n; i++, j <<= 1) it_send_midi( sigrenderer, channel, (unsigned char)(midi->SFmacroz[channel->SFmacro] & j ? entry->effectvalue : midi->SFmacro[channel->SFmacro] [i])); } } break; case IT_XM_SET_ENVELOPE_POSITION: if (channel->playing && channel->playing->env_instrument) { IT_ENVELOPE *envelope = &channel->playing->env_instrument->volume_envelope; if (envelope->flags & IT_ENVELOPE_ON) { IT_PLAYING_ENVELOPE *pe = &channel->playing->volume_envelope; pe->tick = entry->effectvalue; if (pe->tick >= envelope->node_t[envelope->n_nodes - 1]) pe->tick = envelope->node_t[envelope->n_nodes - 1]; pe->next_node = 0; while (pe->tick > envelope->node_t[pe->next_node]) pe->next_node++; xm_envelope_calculate_value(envelope, pe); } } break; /* uggly plain portamento for now */ case IT_PTM_NOTE_SLIDE_DOWN: case IT_PTM_NOTE_SLIDE_DOWN_RETRIG: { channel->toneslide_retrig = (entry->effect == IT_PTM_NOTE_SLIDE_DOWN_RETRIG); if (channel->ptm_last_toneslide) { channel->toneslide_tick = channel->last_toneslide_tick; if (--channel->toneslide_tick == 0) { channel->truenote += channel->toneslide; if (channel->truenote >= 120) { if (channel->toneslide < 0) channel->truenote = 0; else channel->truenote = 119; } channel->note += channel->toneslide; if (channel->note >= 120) { if (channel->toneslide < 0) channel->note = 0; else channel->note = 119; } if (channel->playing) { if (channel->sample) channel->playing->note = channel->truenote; else channel->playing->note = channel->note; it_playing_reset_resamplers(channel->playing, 0); channel->playing->declick_stage = 0; } } } channel->ptm_last_toneslide = 0; channel->toneslide = -(entry->effectvalue & 15); channel->ptm_toneslide = (entry->effectvalue & 0xF0) >> 4; channel->toneslide_tick += channel->ptm_toneslide; } break; case IT_PTM_NOTE_SLIDE_UP: case IT_PTM_NOTE_SLIDE_UP_RETRIG: { channel->toneslide_retrig = (entry->effect == IT_PTM_NOTE_SLIDE_UP_RETRIG); if (channel->ptm_last_toneslide) { channel->toneslide_tick = channel->last_toneslide_tick; if (--channel->toneslide_tick == 0) { channel->truenote += channel->toneslide; if (channel->truenote >= 120) { if (channel->toneslide < 0) channel->truenote = 0; else channel->truenote = 119; } channel->note += channel->toneslide; if (channel->note >= 120) { if (channel->toneslide < 0) channel->note = 0; else channel->note = 119; } if (channel->playing) { if (channel->sample) channel->playing->note = channel->truenote; else channel->playing->note = channel->note; it_playing_reset_resamplers(channel->playing, 0); channel->playing->declick_stage = 0; } } } channel->ptm_last_toneslide = 0; channel->toneslide = -(entry->effectvalue & 15); channel->ptm_toneslide = (entry->effectvalue & 0xF0) >> 4; channel->toneslide_tick += channel->ptm_toneslide; } break; case IT_OKT_NOTE_SLIDE_DOWN: case IT_OKT_NOTE_SLIDE_DOWN_ROW: channel->toneslide = -entry->effectvalue; channel->okt_toneslide = (entry->effect == IT_OKT_NOTE_SLIDE_DOWN) ? 255 : 1; break; case IT_OKT_NOTE_SLIDE_UP: case IT_OKT_NOTE_SLIDE_UP_ROW: channel->toneslide = entry->effectvalue; channel->okt_toneslide = (entry->effect == IT_OKT_NOTE_SLIDE_UP) ? 255 : 1; break; case IT_OKT_ARPEGGIO_3: case IT_OKT_ARPEGGIO_4: case IT_OKT_ARPEGGIO_5: { channel->arpeggio_offsets[0] = 0; channel->arpeggio_offsets[1] = -(entry->effectvalue >> 4); channel->arpeggio_offsets[2] = entry->effectvalue & 0x0F; switch (entry->effect) { case IT_OKT_ARPEGGIO_3: channel->arpeggio_table = (const unsigned char *)&arpeggio_okt_3; break; case IT_OKT_ARPEGGIO_4: channel->arpeggio_table = (const unsigned char *)&arpeggio_okt_4; break; case IT_OKT_ARPEGGIO_5: channel->arpeggio_table = (const unsigned char *)&arpeggio_okt_5; break; } } break; case IT_OKT_VOLUME_SLIDE_DOWN: if (entry->effectvalue <= 16) channel->volslide = -entry->effectvalue; else { channel->volume -= entry->effectvalue - 16; if (channel->volume > 64) channel->volume = 0; } break; case IT_OKT_VOLUME_SLIDE_UP: if (entry->effectvalue <= 16) channel->volslide = entry->effectvalue; else { channel->volume += entry->effectvalue - 16; if (channel->volume > 64) channel->volume = 64; } break; } } if (!(sigdata->flags & IT_WAS_AN_XM)) post_process_it_volpan(sigrenderer, entry); return 0; } static int process_it_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry) { DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; // When tone portamento and instrument are specified: // If Gxx is off: // - same sample, do nothing but portamento // - diff sample, retrigger all but keep current note+slide + do porta // - if instrument is invalid, nothing; if sample is invalid, cut // If Gxx is on: // - same sample or new sample invalid, retrigger envelopes and initialise // note value for portamento to 'seek' to // - diff sample/inst, start using new envelopes // When tone portamento is specified alone, sample won't change. // TODO: consider what happens with instrument alone after all this... if (entry->mask & (IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT)) { if (entry->mask & IT_ENTRY_INSTRUMENT) channel->instrument = entry->instrument; instrument_to_sample(sigdata, channel); if (channel->note <= 120) { if ((sigdata->flags & IT_USE_INSTRUMENTS) && channel->sample == 0) it_retrigger_note(sigrenderer, channel); /* Stop the note */ /*return 1;*/ if (entry->mask & IT_ENTRY_INSTRUMENT) get_default_volpan(sigdata, channel); } else it_retrigger_note(sigrenderer, channel); /* Stop the note */ } /** WARNING: This is not ideal, since channel->playing might not get * allocated owing to lack of memory... */ if (((entry->mask & IT_ENTRY_VOLPAN) && entry->volpan >= 193 && entry->volpan <= 202) || ((entry->mask & IT_ENTRY_EFFECT) && (entry->effect == IT_TONE_PORTAMENTO || entry->effect == IT_VOLSLIDE_TONEPORTA))) { if (channel->playing && (entry->mask & IT_ENTRY_INSTRUMENT)) { if (sigdata->flags & IT_COMPATIBLE_GXX) it_compatible_gxx_retrigger(sigdata, channel); else if ((!(sigdata->flags & IT_USE_INSTRUMENTS) || (channel->instrument >= 1 && channel->instrument <= sigdata->n_instruments)) && channel->sample != channel->playing->sampnum) { unsigned char note = channel->playing->note; int slide = channel->playing->slide; it_retrigger_note(sigrenderer, channel); if (channel->playing) { channel->playing->note = note; channel->playing->slide = slide; // Should we be preserving sample_vibrato_time? depth? } } } channel->toneporta = 0; 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; } channel->toneporta += v << 4; } if ((entry->mask & IT_ENTRY_EFFECT) && (entry->effect == IT_TONE_PORTAMENTO || entry->effect == IT_VOLSLIDE_TONEPORTA)) { /* Tone Portamento in the effect column */ unsigned char v; if (entry->effect == IT_TONE_PORTAMENTO) v = entry->effectvalue; else v = 0; if (sigdata->flags & IT_COMPATIBLE_GXX) { if (v == 0) v = channel->lastG; channel->lastG = v; } else { if (v == 0 && !(sigdata->flags & IT_WAS_A_669)) v = channel->lastEF; channel->lastEF = v; } channel->toneporta += v << 4; } if ((entry->mask & IT_ENTRY_NOTE) || ((sigdata->flags & IT_COMPATIBLE_GXX) && (entry->mask & IT_ENTRY_INSTRUMENT))) { if (channel->note <= 120) { if (channel->sample) channel->destnote = channel->truenote; else channel->destnote = channel->note; } } if (channel->playing) goto skip_start_note; } if ((entry->mask & IT_ENTRY_NOTE) || ((entry->mask & IT_ENTRY_INSTRUMENT) && (!channel->playing || entry->instrument != channel->playing->instnum))) { if (channel->note <= 120) { get_true_pan(sigdata, channel); if ((entry->mask & IT_ENTRY_NOTE) || !(sigdata->flags & (IT_WAS_AN_S3M | IT_WAS_A_PTM))) it_retrigger_note(sigrenderer, channel); } } skip_start_note: if (entry->mask & IT_ENTRY_VOLPAN) { if (entry->volpan <= 64) { /* Volume */ channel->volume = entry->volpan; } else if (entry->volpan <= 74) { /* Fine volume slide up */ unsigned char v = entry->volpan - 65; if (v == 0) v = channel->lastvolslide; channel->lastvolslide = v; /* = effect DxF where x == entry->volpan - 65 */ channel->volume += v; if (channel->volume > 64) channel->volume = 64; } else if (entry->volpan <= 84) { /* Fine volume slide down */ unsigned char v = entry->volpan - 75; if (v == 0) v = channel->lastvolslide; channel->lastvolslide = v; /* = effect DFx where x == entry->volpan - 75 */ channel->volume -= v; if (channel->volume > 64) channel->volume = 0; } else if (entry->volpan < 128) { /* Volume slide up */ /* Volume slide down */ /* Portamento down */ /* Portamento up */ } else if (entry->volpan <= 192) { /* Pan */ channel->pan = entry->volpan - 128; channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; } /* else */ /* Tone Portamento */ /* Vibrato */ } return 0; } static void retrigger_xm_envelopes(IT_PLAYING *playing) { playing->volume_envelope.next_node = 0; playing->volume_envelope.tick = -1; playing->pan_envelope.next_node = 0; playing->pan_envelope.tick = -1; playing->fadeoutcount = 1024; } static void process_xm_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry) { DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; IT_PLAYING *playing = NULL; if (entry->mask & IT_ENTRY_INSTRUMENT) { int oldsample = channel->sample; channel->inv_loop_offset = 0; channel->instrument = entry->instrument; instrument_to_sample(sigdata, channel); if (channel->playing && !((entry->mask & IT_ENTRY_NOTE) && entry->note >= 120) && !((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_XM_KEY_OFF && entry->effectvalue == 0)) { playing = dup_playing(channel->playing, channel, channel); if (!playing) return; if (!(sigdata->flags & IT_WAS_A_MOD)) { /* Retrigger vol/pan envelopes if enabled, and cancel fadeout. * Also reset vol/pan to that of _original_ instrument. */ channel->playing->flags &= ~(IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING); it_playing_update_resamplers(channel->playing); channel->volume = channel->playing->sample->default_volume; channel->truepan = 32 + channel->playing->sample->default_pan * 64; retrigger_xm_envelopes(channel->playing); } else { /* Switch if sample changed */ if (oldsample != channel->sample) { int i; for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (!sigrenderer->playing[i]) { channel->playing->declick_stage = 3; sigrenderer->playing[i] = channel->playing; channel->playing = NULL; break; } } if (!channel->sample) { if (channel->playing) { free_playing(channel->playing); channel->playing = NULL; } } else { if (channel->playing) { free_playing(channel->playing); } channel->playing = playing; playing = NULL; channel->playing->declick_stage = 0; channel->playing->sampnum = channel->sample; channel->playing->sample = &sigdata->sample[channel->sample - 1]; it_playing_reset_resamplers(channel->playing, 0); } } get_default_volpan(sigdata, channel); } } } if (!((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_XM_KEY_OFF && entry->effectvalue == 0) && (entry->mask & IT_ENTRY_NOTE)) { if (!(entry->mask & IT_ENTRY_INSTRUMENT)) instrument_to_sample(sigdata, channel); if (channel->note >= 120) xm_note_off(sigdata, channel); else if (channel->sample == 0) { /** If we get here, one of the following is the case: ** 1. The instrument has never been specified on this channel. ** 2. The specified instrument is invalid. ** 3. The instrument has no sample mapped to the selected note. ** What should happen? ** ** Experimentation shows that any existing note stops and cannot ** be brought back. A subsequent instrument change fixes that. **/ if (channel->playing) { int i; if (playing) { free_playing(channel->playing); channel->playing = playing; playing = NULL; } for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (!sigrenderer->playing[i]) { channel->playing->declick_stage = 3; sigrenderer->playing[i] = channel->playing; channel->playing = NULL; break; } } if (channel->playing) { free_playing(channel->playing); channel->playing = NULL; } } if (playing) free_playing(playing); return; } else if (channel->playing && (entry->mask & IT_ENTRY_VOLPAN) && ((entry->volpan >> 4) == 0xF)) { /* Don't retrigger note; portamento in the volume column. */ } else if (channel->playing && (entry->mask & IT_ENTRY_EFFECT) && (entry->effect == IT_TONE_PORTAMENTO || entry->effect == IT_VOLSLIDE_TONEPORTA)) { /* Don't retrigger note; portamento in the effects column. */ } else { channel->destnote = IT_NOTE_OFF; if (!channel->playing) { channel->playing = new_playing(); if (!channel->playing) { if (playing) free_playing(playing); return; } // Adding the following seems to do the trick for the case where // a piece starts with an instrument alone and then some notes // alone. retrigger_xm_envelopes(channel->playing); } else if (playing) { /* volume rampy stuff! move note to NNA */ int i; IT_PLAYING *ptemp; if (playing->sample) ptemp = playing; else ptemp = channel->playing; if (!ptemp) { if (playing) free_playing(playing); return; } playing = NULL; for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (!sigrenderer->playing[i]) { ptemp->declick_stage = 3; ptemp->flags |= IT_PLAYING_SUSTAINOFF | IT_PLAYING_FADING; sigrenderer->playing[i] = ptemp; ptemp = NULL; break; } } if (ptemp) free_playing(ptemp); } channel->playing->flags = 0; channel->playing->resampling_quality = sigrenderer->resampling_quality; channel->playing->channel = channel; channel->playing->sample = &sigdata->sample[channel->sample - 1]; if (sigdata->flags & IT_USE_INSTRUMENTS) channel->playing->instrument = &sigdata->instrument[channel->instrument - 1]; else channel->playing->instrument = NULL; channel->playing->env_instrument = channel->playing->instrument; channel->playing->sampnum = channel->sample; channel->playing->instnum = channel->instrument; channel->playing->declick_stage = 0; channel->playing->channel_volume = channel->channelvolume; channel->playing->note = channel->truenote; channel->playing->enabled_envelopes = 0; channel->playing->volume_offset = 0; channel->playing->panning_offset = 0; // channel->playing->output = channel->output; if (sigdata->flags & IT_USE_INSTRUMENTS) { IT_PLAYING *playing = channel->playing; IT_INSTRUMENT *instrument = playing->instrument; if (instrument->volume_envelope.flags & IT_ENVELOPE_ON) playing->enabled_envelopes |= IT_ENV_VOLUME; if (instrument->pan_envelope.flags & IT_ENVELOPE_ON) playing->enabled_envelopes |= IT_ENV_PANNING; // if (instrument->output) playing->output = instrument->output; } channel->playing->filter_cutoff = 127; channel->playing->filter_resonance = 0; channel->playing->true_filter_cutoff = 127 << 8; channel->playing->true_filter_resonance = 0; channel->playing->vibrato_speed = 0; channel->playing->vibrato_depth = 0; channel->playing->vibrato_n = 0; channel->playing->vibrato_time = 0; channel->playing->vibrato_waveform = 0; channel->playing->tremolo_speed = 0; channel->playing->tremolo_depth = 0; channel->playing->tremolo_time = 0; channel->playing->tremolo_waveform = 0; channel->playing->panbrello_speed = 0; channel->playing->panbrello_depth = 0; channel->playing->panbrello_time = 0; channel->playing->panbrello_waveform = 0; channel->playing->panbrello_random = 0; channel->playing->sample_vibrato_time = 0; channel->playing->sample_vibrato_waveform = channel->playing->sample->vibrato_waveform; channel->playing->sample_vibrato_depth = 0; channel->playing->slide = 0; channel->playing->finetune = channel->playing->sample->finetune; it_reset_filter_state( &channel->playing->filter_state[0]); // Are these it_reset_filter_state( &channel->playing->filter_state[1]); // necessary? it_playing_reset_resamplers(channel->playing, 0); /** WARNING - is everything initialised? */ } } if (!((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_XM_KEY_OFF && entry->effectvalue == 0) && !((entry->mask & IT_ENTRY_NOTE) && entry->note >= 120) && (entry->mask & (IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT)) == (IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT)) { if (channel->playing) retrigger_xm_envelopes(channel->playing); get_default_volpan(sigdata, channel); } if ((entry->mask & IT_ENTRY_VOLPAN) && ((entry->volpan >> 4) == 0xF)) { /* Tone Portamento */ unsigned char v = (entry->volpan & 15) << 4; if (v == 0) v = channel->lastG; channel->lastG = v; if (entry->mask & IT_ENTRY_NOTE) if (channel->sample && channel->note < 120) channel->destnote = channel->truenote; channel->toneporta = v << 4; } else if ((entry->mask & IT_ENTRY_EFFECT) && (entry->effect == IT_TONE_PORTAMENTO || entry->effect == IT_VOLSLIDE_TONEPORTA)) { unsigned char v; if (entry->effect == IT_TONE_PORTAMENTO) v = entry->effectvalue; else v = 0; if (v == 0) v = channel->lastG; channel->lastG = v; if (entry->mask & IT_ENTRY_NOTE) if (channel->sample && channel->note < 120) channel->destnote = channel->truenote; channel->toneporta = v << 4; } if (entry->mask & IT_ENTRY_VOLPAN) { int effect = entry->volpan >> 4; int value = entry->volpan & 15; switch (effect) { case 0x6: /* Volume slide down */ channel->xm_volslide = -value; break; case 0x7: /* Volume slide up */ channel->xm_volslide = value; break; case 0x8: /* Fine volume slide down */ channel->volume -= value; if (channel->volume > 64) channel->volume = 0; break; case 0x9: /* Fine volume slide up */ channel->volume += value; if (channel->volume > 64) channel->volume = 64; break; case 0xA: /* Set vibrato speed */ if (value) channel->lastHspeed = value; if (channel->playing) channel->playing->vibrato_speed = channel->lastHspeed; break; case 0xB: /* Vibrato */ if (value) channel->lastHdepth = value << 2; /** WARNING: correct ? */ if (channel->playing) { channel->playing->vibrato_depth = channel->lastHdepth; channel->playing->vibrato_speed = channel->lastHspeed; channel->playing->vibrato_n++; } break; case 0xC: /* Set panning */ channel->truepan = 32 + value * (17 * 64); break; case 0xD: /* Pan slide left */ /* -128 is a special case for emulating a 'feature' in FT2. * As soon as effects are processed, it goes hard left. */ channel->panslide = value ? -value : -128; break; case 0xE: /* Pan slide Right */ channel->panslide = value; break; case 0xF: /* Tone porta */ break; default: /* Volume */ channel->volume = entry->volpan - 0x10; break; } } if (playing) free_playing(playing); } /* This function assumes !IT_IS_END_ROW(entry). */ static int process_note_data(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry, int ignore_cxx) { DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; if (sigdata->flags & IT_WAS_AN_XM) process_xm_note_data(sigrenderer, entry); else if (process_it_note_data(sigrenderer, entry)) return 0; return process_effects(sigrenderer, entry, ignore_cxx); } static int process_entry(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry, int ignore_cxx) { IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; if (entry->mask & IT_ENTRY_NOTE) channel->note = entry->note; if ((entry->mask & (IT_ENTRY_NOTE | IT_ENTRY_EFFECT)) && (sigrenderer->sigdata->flags & IT_WAS_A_669)) { reset_channel_effects(channel); // XXX unknown if (channel->playing) channel->playing->finetune = 0; } if ((entry->mask & IT_ENTRY_EFFECT) && entry->effect == IT_S) { /* channel->lastS was set in update_pattern_variables(). */ unsigned char effectvalue = channel->lastS; if (effectvalue >> 4 == IT_S_NOTE_DELAY) { channel->note_delay_count = effectvalue & 15; if (channel->note_delay_count == 0) channel->note_delay_count = 1; channel->note_delay_entry = entry; return 0; } } return process_note_data(sigrenderer, entry, ignore_cxx); } static void update_tick_counts(DUMB_IT_SIGRENDERER *sigrenderer) { int i; for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { IT_CHANNEL *channel = &sigrenderer->channel[i]; if (channel->key_off_count) { channel->key_off_count--; if (channel->key_off_count == 0) xm_note_off(sigrenderer->sigdata, channel); } else if (channel->note_cut_count) { channel->note_cut_count--; if (channel->note_cut_count == 0) { if (sigrenderer->sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_PTM)) channel->volume = 0; else if (channel->playing) { int i; for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (!sigrenderer->playing[i]) { channel->playing->declick_stage = 3; sigrenderer->playing[i] = channel->playing; channel->playing = NULL; break; } } if (channel->playing) { free_playing(channel->playing); channel->playing = NULL; } } } } else if (channel->note_delay_count && channel->note_delay_entry) { channel->note_delay_count--; if (channel->note_delay_count == 0) process_note_data(sigrenderer, channel->note_delay_entry, 0); /* Don't bother checking the return value; if the note * was delayed, there can't have been a speed=0. */ } } } static int envelope_get_y(IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe) { #if 1 (void)envelope; // TODO: remove the parameter return pe->value; #else int ys, ye; int ts, te; int t; if (pe->next_node <= 0) return envelope->node_y[0] << IT_ENVELOPE_SHIFT; if (pe->next_node >= envelope->n_nodes) return envelope->node_y[envelope->n_nodes - 1] << IT_ENVELOPE_SHIFT; ys = envelope->node_y[pe->next_node - 1] << IT_ENVELOPE_SHIFT; ts = envelope->node_t[pe->next_node - 1]; te = envelope->node_t[pe->next_node]; if (ts == te) return ys; ye = envelope->node_y[pe->next_node] << IT_ENVELOPE_SHIFT; t = pe->tick; return ys + (ye - ys) * (t - ts) / (te - ts); #endif } #if 0 static int it_envelope_end(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe) { if (pe->next_node >= envelope->n_nodes) return 1; if (pe->tick < envelope->node_t[pe->next_node]) return 0; if ((envelope->flags & IT_ENVELOPE_LOOP_ON) && envelope->loop_end >= pe->next_node && envelope->node_t[envelope->loop_end] <= pe->tick) return 0; if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF) && envelope->sus_loop_end >= pe->next_node && envelope->node_t[envelope->sus_loop_end] <= pe->tick) return 0; if (envelope->node_t[envelope->n_nodes-1] <= pe->tick) return 1; return 0; } #endif /* Returns 1 when fading should be initiated for a volume envelope. */ static int update_it_envelope(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe, int flags) { if (!(playing->enabled_envelopes & flags) || !envelope->n_nodes) return 0; ASSERT(envelope->n_nodes > 0); if (pe->tick <= 0) pe->value = envelope->node_y[0] << IT_ENVELOPE_SHIFT; else if (pe->tick >= envelope->node_t[envelope->n_nodes - 1]) { 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); } } pe->tick++; recalculate_it_envelope_node(pe, envelope); if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) { if (pe->tick > envelope->node_t[envelope->sus_loop_end]) { pe->next_node = envelope->sus_loop_start + 1; 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->tick > envelope->node_t[envelope->loop_end]) { pe->next_node = envelope->loop_start + 1; ASSERT(pe->next_node <= envelope->n_nodes); pe->tick = envelope->node_t[envelope->loop_start]; return 0; } } else if (pe->tick > envelope->node_t[envelope->n_nodes - 1]) return 1; return 0; } static void update_it_envelopes(IT_PLAYING *playing) { IT_ENVELOPE *envelope = &playing->env_instrument->volume_envelope; IT_PLAYING_ENVELOPE *pe = &playing->volume_envelope; if (update_it_envelope(playing, envelope, pe, IT_ENV_VOLUME)) { playing->flags |= IT_PLAYING_FADING; if (pe->value == 0) playing->flags |= IT_PLAYING_DEAD; } update_it_envelope(playing, &playing->env_instrument->pan_envelope, &playing->pan_envelope, IT_ENV_PANNING); update_it_envelope(playing, &playing->env_instrument->pitch_envelope, &playing->pitch_envelope, IT_ENV_PITCH); } static int xm_envelope_is_sustaining(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe) { if ((envelope->flags & IT_ENVELOPE_SUSTAIN_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) if (envelope->sus_loop_start < envelope->n_nodes) if (pe->tick == envelope->node_t[envelope->sus_loop_start]) return 1; return 0; } static void update_xm_envelope(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe) { if (!(envelope->flags & IT_ENVELOPE_ON)) return; if (xm_envelope_is_sustaining(playing, envelope, pe)) return; if (pe->tick >= envelope->node_t[envelope->n_nodes - 1]) return; pe->tick++; /* pe->next_node must be kept up to date for envelope_get_y(). */ while (pe->tick > envelope->node_t[pe->next_node]) pe->next_node++; if ((envelope->flags & IT_ENVELOPE_LOOP_ON) && envelope->loop_end < envelope->n_nodes) { if (pe->tick == envelope->node_t[envelope->loop_end]) { pe->next_node = MID(0, envelope->loop_start, envelope->n_nodes - 1); pe->tick = envelope->node_t[pe->next_node]; } } xm_envelope_calculate_value(envelope, pe); } static void update_xm_envelopes(IT_PLAYING *playing) { update_xm_envelope(playing, &playing->env_instrument->volume_envelope, &playing->volume_envelope); update_xm_envelope(playing, &playing->env_instrument->pan_envelope, &playing->pan_envelope); } static void update_fadeout(DUMB_IT_SIGDATA *sigdata, IT_PLAYING *playing) { if (playing->flags & IT_PLAYING_FADING) { playing->fadeoutcount -= playing->env_instrument->fadeout; if (playing->fadeoutcount <= 0) { playing->fadeoutcount = 0; if (!(sigdata->flags & IT_WAS_AN_XM)) playing->flags |= IT_PLAYING_DEAD; } } } static int apply_pan_envelope(IT_PLAYING *playing); static float calculate_volume(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float volume); static void playing_volume_setup(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float invt2g) { DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; int pan; float vol, span; float rampScale; int ramp_style = sigrenderer->ramp_style; pan = apply_pan_envelope(playing); if ((sigrenderer->n_channels >= 2) && (sigdata->flags & IT_STEREO) && (sigrenderer->n_channels != 3 || !IT_IS_SURROUND_SHIFTED(pan))) { if (!IT_IS_SURROUND_SHIFTED(pan)) { span = (pan - (32 << 8)) * sigdata->pan_separation * (1.0f / ((32 << 8) * 128)); vol = 0.5f * (1.0f - span); playing->float_volume[0] = vol; playing->float_volume[1] = 1.0f - vol; } else { playing->float_volume[0] = -0.5f; playing->float_volume[1] = 0.5f; } } else { playing->float_volume[0] = 1.0f; playing->float_volume[1] = 1.0f; } vol = calculate_volume(sigrenderer, playing, 1.0f); playing->float_volume[0] *= vol; playing->float_volume[1] *= vol; rampScale = 4; if (ramp_style > 0 && playing->declick_stage == 2) { if ((playing->ramp_volume[0] == 0 && playing->ramp_volume[1] == 0) || vol == 0) rampScale = 48; } if (ramp_style == 0 || (ramp_style < 2 && playing->declick_stage == 2)) { if (playing->declick_stage <= 2) { playing->ramp_volume[0] = playing->float_volume[0]; playing->ramp_volume[1] = playing->float_volume[1]; playing->declick_stage = 2; } else { playing->float_volume[0] = 0; playing->float_volume[1] = 0; playing->ramp_volume[0] = 0; playing->ramp_volume[1] = 0; playing->declick_stage = 5; } playing->ramp_delta[0] = 0; playing->ramp_delta[1] = 0; } else { if (playing->declick_stage == 0) { playing->ramp_volume[0] = 0; playing->ramp_volume[1] = 0; rampScale = 48; playing->declick_stage++; } else if (playing->declick_stage == 1) { rampScale = 48; } else if (playing->declick_stage >= 3) { playing->float_volume[0] = 0; playing->float_volume[1] = 0; if (playing->declick_stage == 3) playing->declick_stage++; rampScale = 48; } playing->ramp_delta[0] = rampScale * invt2g * (playing->float_volume[0] - playing->ramp_volume[0]); playing->ramp_delta[1] = rampScale * invt2g * (playing->float_volume[1] - playing->ramp_volume[1]); } } static void process_playing(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float invt2g) { DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; if (playing->instrument) { if (sigdata->flags & IT_WAS_AN_XM) update_xm_envelopes(playing); else update_it_envelopes(playing); update_fadeout(sigdata, playing); } playing_volume_setup(sigrenderer, playing, invt2g); if (sigdata->flags & IT_WAS_AN_XM) { /* 'depth' is used to store the tick number for XM files. */ if (playing->sample_vibrato_depth < playing->sample->vibrato_rate) playing->sample_vibrato_depth++; } else { playing->sample_vibrato_depth += playing->sample->vibrato_rate; if (playing->sample_vibrato_depth > playing->sample->vibrato_depth << 8) playing->sample_vibrato_depth = playing->sample->vibrato_depth << 8; } playing->sample_vibrato_time += playing->sample->vibrato_speed; } #if (defined(_MSC_VER) && _MSC_VER < 1800) || defined(__ANDROID__) static float log2(float x) { return (float)log(x) / (float)log(2.0f); } #endif static int delta_to_note(float delta, int base) { float note; note = log2(delta * 65536.f / (float)base) * 12.0f + 60.5f; if (note > 119) note = 119; else if (note < 0) note = 0; return (int)note; } // Period table for Protracker octaves 0-5: #if 0 static const unsigned short ProTrackerPeriodTable[6*12] = { 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907, 856,808,762,720,678,640,604,570,538,508,480,453, 428,404,381,360,339,320,302,285,269,254,240,226, 214,202,190,180,170,160,151,143,135,127,120,113, 107,101,95,90,85,80,75,71,67,63,60,56, 53,50,47,45,42,40,37,35,33,31,30,28 }; static const unsigned short ProTrackerTunedPeriods[16*12] = { 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907, 1700,1604,1514,1430,1348,1274,1202,1134,1070,1010,954,900, 1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,894, 1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,888, 1664,1570,1482,1398,1320,1246,1176,1110,1048,990,934,882, 1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,874, 1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,868, 1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914,862, 1814,1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960, 1800,1700,1604,1514,1430,1350,1272,1202,1134,1070,1010,954, 1788,1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948, 1774,1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940, 1762,1664,1570,1482,1398,1320,1246,1176,1110,1048,988,934, 1750,1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926, 1736,1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920, 1724,1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914 }; #endif static void process_all_playing(DUMB_IT_SIGRENDERER *sigrenderer) { DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; int i; float invt2g = 1.0f / ((float)TICK_TIME_DIVIDEND / (float)sigrenderer->tempo / 256.0f); for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { IT_CHANNEL *channel = &sigrenderer->channel[i]; IT_PLAYING *playing = channel->playing; if (playing) { int vibrato_shift; switch (playing->vibrato_waveform) { default: vibrato_shift = it_sine[playing->vibrato_time]; break; case 1: vibrato_shift = it_sawtooth[playing->vibrato_time]; break; case 2: vibrato_shift = it_squarewave[playing->vibrato_time]; break; case 3: vibrato_shift = (rand() % 129) - 64; break; case 4: vibrato_shift = it_xm_squarewave[playing->vibrato_time]; break; case 5: vibrato_shift = it_xm_ramp[playing->vibrato_time]; break; case 6: vibrato_shift = it_xm_ramp[255 - playing->vibrato_time]; break; } vibrato_shift *= playing->vibrato_n; vibrato_shift *= playing->vibrato_depth; vibrato_shift >>= 4; if (sigdata->flags & IT_OLD_EFFECTS) vibrato_shift = -vibrato_shift; playing->volume = channel->volume; playing->pan = channel->truepan; if (playing->volume_offset) { playing->volume += (playing->volume_offset * playing->volume) >> 7; if (playing->volume > 64) { if (playing->volume_offset < 0) playing->volume = 0; else playing->volume = 64; } } if (playing->panning_offset && !IT_IS_SURROUND_SHIFTED(playing->pan)) { playing->pan += playing->panning_offset << IT_ENVELOPE_SHIFT; if (playing->pan > 64 << IT_ENVELOPE_SHIFT) { if (playing->panning_offset < 0) playing->pan = 0; else playing->pan = 64 << IT_ENVELOPE_SHIFT; } } if (sigdata->flags & IT_LINEAR_SLIDES) { int currpitch = ((playing->note - 60) << 8) + playing->slide + vibrato_shift + playing->finetune; /* We add a feature here, which is that of keeping the pitch * within range. Otherwise it crashes. Trust me. It happened. * The limit 32768 gives almost 11 octaves either way. */ if (currpitch < -32768) currpitch = -32768; else if (currpitch > 32767) currpitch = 32767; playing->delta = (float)pow(DUMB_PITCH_BASE, currpitch); playing->delta *= playing->sample->C5_speed * (1.f / 65536.0f); } else { int slide = playing->slide + vibrato_shift; playing->delta = (float)pow(DUMB_PITCH_BASE, ((60 - playing->note) << 8) - playing->finetune); /* playing->delta is 1.0 for C-5, 0.5 for C-6, etc. */ playing->delta *= 1.0f / playing->sample->C5_speed; playing->delta -= slide / AMIGA_DIVISOR; if (playing->delta < (1.0f / 65536.0f) / 32768.0f) { // Should XM notes die if Amiga slides go out of range? playing->flags |= IT_PLAYING_DEAD; playing->delta = 1. / 32768.; continue; } playing->delta = (1.0f / 65536.0f) / playing->delta; } if (playing->channel->glissando && playing->channel->toneporta && playing->channel->destnote < 120) { playing->delta = (float)pow(DUMB_SEMITONE_BASE, delta_to_note(playing->delta, (int)playing->sample->C5_speed) - 60) * playing->sample->C5_speed * (1.f / 65536.f); } /* if ( channel->arpeggio ) { // another FT2 bug... if ((sigdata->flags & (IT_LINEAR_SLIDES|IT_WAS_AN_XM|IT_WAS_A_MOD)) == (IT_WAS_AN_XM|IT_LINEAR_SLIDES) && playing->flags & IT_PLAYING_SUSTAINOFF) { if ( channel->arpeggio > 0xFF ) playing->delta = playing->sample->C5_speed * (1.f / 65536.f); } else*/ { int tick = sigrenderer->tick - 1; if ((sigrenderer->sigdata->flags & (IT_WAS_AN_XM | IT_WAS_A_MOD)) != IT_WAS_AN_XM) tick = sigrenderer->speed - tick - 1; else if (tick == sigrenderer->speed - 1) tick = 0; else ++tick; if (sigrenderer->sigdata->flags & IT_WAS_AN_STM) tick /= 16; playing->delta *= (float)pow( DUMB_SEMITONE_BASE, channel ->arpeggio_offsets[channel->arpeggio_table[tick & 31]]); } /* }*/ playing->filter_cutoff = channel->filter_cutoff; playing->filter_resonance = channel->filter_resonance; } } for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { if (sigrenderer->channel[i].playing) { process_playing(sigrenderer, sigrenderer->channel[i].playing, invt2g); if (!(sigdata->flags & IT_WAS_AN_XM)) { // if ((sigrenderer->channel[i].playing->flags & // (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) == // (IT_PLAYING_BACKGROUND | IT_PLAYING_DEAD)) { // This change was made so Gxx would work correctly when a note // faded out or whatever. Let's hope nothing else was broken by // it. if (sigrenderer->channel[i].playing->flags & IT_PLAYING_DEAD) { free_playing(sigrenderer->channel[i].playing); sigrenderer->channel[i].playing = NULL; } } } } for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (sigrenderer->playing[i]) { process_playing(sigrenderer, sigrenderer->playing[i], invt2g); if (sigrenderer->playing[i]->flags & IT_PLAYING_DEAD) { free_playing(sigrenderer->playing[i]); sigrenderer->playing[i] = NULL; } } } } static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) { DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; if (sigrenderer->tempo < 32 || sigrenderer->tempo > 255) // problematic return 1; // Set note vol/freq to vol/freq set for each channel if (sigrenderer->speed && --sigrenderer->tick == 0) { reset_tick_counts(sigrenderer); sigrenderer->tick = sigrenderer->speed; sigrenderer->rowcount--; if (sigrenderer->rowcount == 0) { sigrenderer->rowcount = 1; #ifdef BIT_ARRAY_BULLSHIT if (sigrenderer->n_rows) { #if 1 /* if (bit_array_test(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row)) { if (sigrenderer->callbacks->loop) { if ((*sigrenderer->callbacks->loop)(sigrenderer->callbacks->loop_data)) return 1; bit_array_reset(sigrenderer->played); if (sigrenderer->speed == 0) goto speed0; I love goto } } */ #endif bit_array_set(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row); { int n; for (n = 0; n < DUMB_IT_N_CHANNELS; n++) { IT_CHANNEL *channel = &sigrenderer->channel[n]; if (channel->played_patjump) { if (channel->played_patjump_order == sigrenderer->order) { bit_array_set(channel->played_patjump, sigrenderer->row); } /* else if ((channel->played_patjump_order & 0x7FFF) == sigrenderer->order) { channel->played_patjump_order |= 0x4000; } else if ((channel->played_patjump_order & 0x3FFF) == sigrenderer->order) { if ((sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD)) == IT_WAS_AN_XM) { joy, was XM, pattern loop bug triggered break to row in same order bit_array_mask(sigrenderer->played, channel->played_patjump, sigrenderer->order * 256); } bit_array_destroy(channel->played_patjump); channel->played_patjump = 0; channel->played_patjump_order = 0xFFFE; } */ else { bit_array_destroy(channel->played_patjump); channel->played_patjump = 0; channel->played_patjump_order = 0xFFFE; } } } } } #endif sigrenderer->processrow++; if (sigrenderer->processrow >= sigrenderer->n_rows) { IT_PATTERN *pattern; int n; int processorder = sigrenderer->processorder; if ((sigrenderer->processrow | 0xC00) == 0xFFFE + 1) { /* It was incremented above! */ sigrenderer->processrow = sigrenderer->breakrow; sigrenderer->breakrow = 0; for (n = 0; n < DUMB_IT_N_CHANNELS; n++) sigrenderer->channel[n].pat_loop_end_row = 0; } else { sigrenderer->processrow = sigrenderer->breakrow; sigrenderer->breakrow = 0; // XXX lolwut } if (sigrenderer->processorder == 0xFFFF) sigrenderer->processorder = sigrenderer->order - 1; for (;;) { sigrenderer->processorder++; if (sigrenderer->processorder >= sigdata->n_orders) { sigrenderer->processorder = sigrenderer->restart_position; if (sigrenderer->processorder >= sigdata->n_orders) { /* Restarting beyond end. We'll loop for now. */ sigrenderer->processorder = -1; continue; } if (sigdata->flags & IT_WAS_AN_OKT) { /* Reset some things */ sigrenderer->speed = sigdata->speed; sigrenderer->tempo = sigdata->tempo; for (n = 0; n < DUMB_IT_N_CHANNELS; n++) { xm_note_off(sigdata, &sigrenderer->channel[n]); } } } n = sigdata->order[sigrenderer->processorder]; if (n < sigdata->n_patterns) break; #ifdef INVALID_ORDERS_END_SONG if (n != IT_ORDER_SKIP) #else if (n == IT_ORDER_END) #endif { sigrenderer->processorder = sigrenderer->restart_position - 1; } #ifdef BIT_ARRAY_BULLSHIT /* Fix play tracking and timekeeping for orders containing * skip commands */ for (n = 0; n < 256; n++) { bit_array_set(sigrenderer->played, sigrenderer->processorder * 256 + n); timekeeping_array_push(sigrenderer->row_timekeeper, sigrenderer->processorder * 256 + n, sigrenderer->time_played); timekeeping_array_bump(sigrenderer->row_timekeeper, sigrenderer->processorder * 256 + n); } #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? */ if (pattern->entry) { sigrenderer->entry = sigrenderer->entry_start = pattern->entry; sigrenderer->entry_end = sigrenderer->entry + pattern->n_entries; } else { sigrenderer->entry = sigrenderer->entry_start = 0; sigrenderer->entry_end = 0; } /* If n_rows was 0, we're only just starting. Don't do anything * weird here. */ /* added: process row check, for break to row spooniness */ if (n && (processorder == 0xFFFF ? sigrenderer->order > sigrenderer->processorder : sigrenderer->order >= sigrenderer->processorder) #ifdef BIT_ARRAY_BULLSHIT && bit_array_test(sigrenderer->played, sigrenderer->processorder * 256 + sigrenderer->processrow) #endif ) { #ifdef BIT_ARRAY_BULLSHIT sigrenderer->looped = 1; #endif if (sigrenderer->callbacks->loop) { if ((*sigrenderer->callbacks->loop)( sigrenderer->callbacks->loop_data)) return 1; #ifdef BIT_ARRAY_BULLSHIT bit_array_reset(sigrenderer->played); #endif if (sigrenderer->speed == 0) goto speed0; /* I love goto */ } } sigrenderer->order = sigrenderer->processorder; n = sigrenderer->processrow; while (n) { while (sigrenderer->entry < sigrenderer->entry_end) { if (IT_IS_END_ROW(sigrenderer->entry)) { sigrenderer->entry++; break; } sigrenderer->entry++; } n--; } sigrenderer->row = sigrenderer->processrow; } else { if (sigrenderer->entry) { while (sigrenderer->entry < sigrenderer->entry_end) { if (IT_IS_END_ROW(sigrenderer->entry)) { sigrenderer->entry++; break; } sigrenderer->entry++; } sigrenderer->row++; } else { #ifdef BIT_ARRAY_BULLSHIT bit_array_clear(sigrenderer->played, sigrenderer->order * 256); #endif sigrenderer->entry = sigrenderer->entry_start; sigrenderer->row = 0; } } #ifdef BIT_ARRAY_BULLSHIT if (sigrenderer->looped == 0) { timekeeping_array_push(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row, sigrenderer->time_played); } timekeeping_array_bump(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row); #endif if (!(sigdata->flags & IT_WAS_A_669)) reset_effects(sigrenderer); if (sigrenderer->entry) { 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_WAS_AN_OKT) update_effects(sigrenderer); else if (!(sigdata->flags & IT_OLD_EFFECTS)) update_smooth_effects(sigrenderer); } else { if (sigrenderer->entry) { IT_ENTRY *entry = sigrenderer->entry; while (entry < sigrenderer->entry_end && !IT_IS_END_ROW(entry)) { if (entry->mask & IT_ENTRY_EFFECT && entry->effect != IT_SET_SAMPLE_OFFSET) process_effects(sigrenderer, entry, 0); /* Don't bother checking the return value; if there * was a pattern delay, there can't be a speed=0. */ entry++; } } update_effects(sigrenderer); } } else { if (!(sigdata->flags & IT_WAS_AN_STM) || !(sigrenderer->tick & 15)) { speed0: update_effects(sigrenderer); update_tick_counts(sigrenderer); } } if (sigrenderer->globalvolume == 0) { if (sigrenderer->callbacks->global_volume_zero) { LONG_LONG t = sigrenderer->gvz_sub_time + ((TICK_TIME_DIVIDEND / (sigrenderer->tempo << 8)) << 16); sigrenderer->gvz_time += (int)(t >> 16); sigrenderer->gvz_sub_time = (int)t & 65535; if (sigrenderer->gvz_time >= 65536 * 12) { #ifdef BIT_ARRAY_BULLSHIT sigrenderer->looped = 1; #endif if ((*sigrenderer->callbacks->global_volume_zero)( sigrenderer->callbacks->global_volume_zero_data)) return 1; } } } else { if (sigrenderer->callbacks->global_volume_zero) { sigrenderer->gvz_time = 0; sigrenderer->gvz_sub_time = 0; } } process_all_playing(sigrenderer); { LONG_LONG t = (TICK_TIME_DIVIDEND / (sigrenderer->tempo << 8)) << 16; if (sigrenderer->sigdata->flags & IT_WAS_AN_STM) { t /= 16; } t += sigrenderer->sub_time_left; sigrenderer->time_left += (int)(t >> 16); sigrenderer->sub_time_left = (int)t & 65535; } return 0; } int dumb_it_max_to_mix = 64; #if 0 static const int aiMODVol[] = { 0, 16, 24, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256, 272, 288, 304, 320, 336, 352, 368, 384, 400, 416, 432, 448, 464, 480, 496, 529, 545, 561, 577, 593, 609, 625, 641, 657, 673, 689, 705, 721, 737, 753, 769, 785, 801, 817, 833, 849, 865, 881, 897, 913, 929, 945, 961, 977, 993, 1009, 1024 }; #endif static const int aiPTMVolScaled[] = { 0, 31, 54, 73, 96, 111, 130, 153, 172, 191, 206, 222, 237, 252, 275, 298, 317, 336, 351, 370, 386, 401, 416, 428, 443, 454, 466, 477, 489, 512, 531, 553, 573, 592, 611, 626, 645, 660, 679, 695, 710, 725, 740, 756, 767, 782, 798, 809, 820, 836, 847, 859, 870, 881, 897, 908, 916, 927, 939, 950, 962, 969, 983, 1005, 1024}; static float calculate_volume(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float volume) { if (volume != 0) { int vol; if (playing->channel->flags & IT_CHANNEL_MUTED) return 0; if ((playing->channel->tremor_time & 192) == 128) return 0; switch (playing->tremolo_waveform) { default: vol = it_sine[playing->tremolo_time]; break; case 1: vol = it_sawtooth[playing->tremolo_time]; break; case 2: vol = it_squarewave[playing->tremolo_time]; break; case 3: vol = (rand() % 129) - 64; break; case 4: vol = it_xm_squarewave[playing->tremolo_time]; break; case 5: vol = it_xm_ramp[playing->tremolo_time]; break; case 6: vol = it_xm_ramp[255 - ((sigrenderer->sigdata->flags & IT_WAS_A_MOD) ? playing->vibrato_time : playing->tremolo_time)]; break; } vol *= playing->tremolo_depth; vol = (playing->volume << 5) + vol; if (vol <= 0) return 0; if (vol > 64 << 5) vol = 64 << 5; if (sigrenderer->sigdata->flags & IT_WAS_A_PTM) { int v = aiPTMVolScaled[vol >> 5]; if (vol < 64 << 5) { int f = vol & ((1 << 5) - 1); int f2 = (1 << 5) - f; int v2 = aiPTMVolScaled[(vol >> 5) + 1]; v = (v * f2 + v2 * f) >> 5; } vol = v << 1; } volume *= vol; /* 64 << 5 */ volume *= playing->sample->global_volume; /* 64 */ volume *= playing->channel_volume; /* 64 */ volume *= sigrenderer->globalvolume; /* 128 */ volume *= sigrenderer->sigdata->mixing_volume; /* 128 */ volume *= 1.0f / ((64 << 5) * 64.0f * 64.0f * 128.0f * 128.0f); if (volume && playing->instrument) { if (playing->enabled_envelopes & IT_ENV_VOLUME && playing->env_instrument->volume_envelope.n_nodes) { volume *= envelope_get_y(&playing->env_instrument->volume_envelope, &playing->volume_envelope); volume *= 1.0f / (64 << IT_ENVELOPE_SHIFT); } volume *= playing->instrument->global_volume; /* 128 */ volume *= playing->fadeoutcount; /* 1024 */ volume *= 1.0f / (128.0f * 1024.0f); } } return volume; } static int apply_pan_envelope(IT_PLAYING *playing) { if (playing->pan <= 64 << IT_ENVELOPE_SHIFT) { int pan; if (playing->panbrello_depth) { switch (playing->panbrello_waveform) { default: pan = it_sine[playing->panbrello_time]; break; case 1: pan = it_sawtooth[playing->panbrello_time]; break; case 2: pan = it_squarewave[playing->panbrello_time]; break; case 3: pan = playing->panbrello_random; break; } pan *= playing->panbrello_depth << 3; pan += playing->pan; if (pan < 0) pan = 0; else if (pan > 64 << IT_ENVELOPE_SHIFT) pan = 64 << IT_ENVELOPE_SHIFT; } else { pan = playing->pan; } if (playing->env_instrument && (playing->enabled_envelopes & IT_ENV_PANNING)) { int p = envelope_get_y(&playing->env_instrument->pan_envelope, &playing->pan_envelope); if (pan > 32 << IT_ENVELOPE_SHIFT) p *= (64 << IT_ENVELOPE_SHIFT) - pan; else p *= pan; pan += p >> (5 + IT_ENVELOPE_SHIFT); } return pan; } return playing->pan; } /* Note: if a click remover is provided, and store_end_sample is set, then * the end point will be computed twice. This situation should not arise. */ static long render_playing(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing, float volume, float main_delta, float delta, long pos, long size, sample_t **samples, int store_end_sample, int *left_to_mix) { int bits; long size_rendered; DUMB_VOLUME_RAMP_INFO lvol, rvol; if (playing->flags & IT_PLAYING_DEAD) return 0; if (*left_to_mix <= 0) volume = 0; { int quality = sigrenderer->resampling_quality; if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality) quality = playing->sample->max_resampling_quality; playing->resampler.quality = quality; resampler_set_quality(playing->resampler.fir_resampler[0], quality); resampler_set_quality(playing->resampler.fir_resampler[1], quality); } bits = playing->sample->flags & IT_SAMPLE_16BIT ? 16 : 8; if (volume == 0) { if (playing->sample->flags & IT_SAMPLE_STEREO) size_rendered = dumb_resample_n_2_1(bits, &playing->resampler, NULL, size, 0, 0, delta); else size_rendered = dumb_resample_n_1_1(bits, &playing->resampler, NULL, size, 0, delta); } else { lvol.volume = playing->ramp_volume[0]; rvol.volume = playing->ramp_volume[1]; lvol.delta = playing->ramp_delta[0] * main_delta; rvol.delta = playing->ramp_delta[1] * main_delta; lvol.target = playing->float_volume[0]; rvol.target = playing->float_volume[1]; rvol.mix = lvol.mix = volume; lvol.declick_stage = rvol.declick_stage = playing->declick_stage; if (sigrenderer->n_channels >= 2) { 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) { 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, &lvol, &click); dumb_record_click(sigrenderer->click_remover[0], pos, click); } size_rendered = dumb_resample_n_1_1(bits, &playing->resampler, samples[0] + pos, size, &lvol, delta); if (store_end_sample) dumb_resample_get_current_sample_n_1_1( bits, &playing->resampler, &lvol, &samples[0][pos + size_rendered]); if (sigrenderer->click_remover) { sample_t click; dumb_resample_get_current_sample_n_1_1( bits, &playing->resampler, &lvol, &click); dumb_record_click(sigrenderer->click_remover[0], pos + size_rendered, -click); } } } playing->ramp_volume[0] = lvol.volume; playing->ramp_volume[1] = rvol.volume; playing->declick_stage = (lvol.declick_stage > rvol.declick_stage) ? lvol.declick_stage : rvol.declick_stage; if (playing->declick_stage >= 4) playing->flags |= IT_PLAYING_DEAD; (*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; switch (playing->sample_vibrato_waveform) { default: sample_vibrato_shift = it_sine[playing->sample_vibrato_time]; break; case 1: sample_vibrato_shift = it_sawtooth[playing->sample_vibrato_time]; break; case 2: sample_vibrato_shift = it_squarewave[playing->sample_vibrato_time]; break; case 3: sample_vibrato_shift = (rand() % 129) - 64; break; case 4: sample_vibrato_shift = it_xm_squarewave[playing->sample_vibrato_time]; break; case 5: sample_vibrato_shift = it_xm_ramp[playing->sample_vibrato_time]; break; case 6: sample_vibrato_shift = it_xm_ramp[255 - playing->sample_vibrato_time]; break; } if (sigdata->flags & IT_WAS_AN_XM) { int depth = playing->sample->vibrato_depth; /* True depth */ if (playing->sample->vibrato_rate) { depth *= playing->sample_vibrato_depth; /* Tick number */ depth /= playing->sample->vibrato_rate; /* XM sweep */ } sample_vibrato_shift *= depth; } else sample_vibrato_shift *= playing->sample_vibrato_depth >> 8; sample_vibrato_shift >>= 4; if (sample_vibrato_shift) { if ((sigdata->flags & IT_LINEAR_SLIDES) || !(sigdata->flags & IT_WAS_AN_XM)) *delta *= (float)pow(DUMB_PITCH_BASE, sample_vibrato_shift); else { /* complicated! */ float scale = *delta / playing->delta; *delta = (1.0f / 65536.0f) / playing->delta; *delta -= sample_vibrato_shift / AMIGA_DIVISOR; if (*delta < (1.0f / 65536.0f) / 32767.0f) { *delta = (1.0f / 65536.0f) / 32767.0f; } *delta = (1.0f / 65536.0f) / *delta * scale; } } } if (playing->env_instrument && (playing->enabled_envelopes & IT_ENV_PITCH)) { int p = envelope_get_y(&playing->env_instrument->pitch_envelope, &playing->pitch_envelope); if (playing->env_instrument->pitch_envelope.flags & IT_ENVELOPE_PITCH_IS_FILTER) *cutoff = (*cutoff * (p + (32 << IT_ENVELOPE_SHIFT))) >> (6 + IT_ENVELOPE_SHIFT); else *delta *= (float)pow(DUMB_PITCH_BASE, p >> (IT_ENVELOPE_SHIFT - 7)); } } static void render_normal(DUMB_IT_SIGRENDERER *sigrenderer, float volume, float delta, long pos, long size, sample_t **samples) { int i; int n_to_mix = 0; IT_TO_MIX to_mix[DUMB_IT_TOTAL_CHANNELS]; int left_to_mix = dumb_it_max_to_mix; sample_t **samples_to_filter = NULL; // int max_output = sigrenderer->max_output; for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { if (sigrenderer->channel[i].playing && !(sigrenderer->channel[i].playing->flags & IT_PLAYING_DEAD)) { to_mix[n_to_mix].playing = sigrenderer->channel[i].playing; to_mix[n_to_mix].volume = volume == 0 ? 0 : calculate_volume(sigrenderer, sigrenderer->channel[i].playing, volume); n_to_mix++; } } for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (sigrenderer ->playing[i]) { /* Won't be dead; it would have been freed. */ to_mix[n_to_mix].playing = sigrenderer->playing[i]; to_mix[n_to_mix].volume = volume == 0 ? 0 : calculate_volume(sigrenderer, sigrenderer->playing[i], volume); n_to_mix++; } } if (volume != 0) qsort(to_mix, n_to_mix, sizeof(IT_TO_MIX), &it_to_mix_compare); for (i = 0; i < n_to_mix; i++) { IT_PLAYING *playing = to_mix[i].playing; float note_delta = delta * playing->delta; int cutoff = playing->filter_cutoff << IT_ENVELOPE_SHIFT; // int output = min( playing->output, max_output ); apply_pitch_modifications(sigrenderer->sigdata, playing, ¬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 (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, delta, 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, volume, delta, 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 /*output*/], pos, samples_to_filter[0], size_rendered, 2, (int)(65536.0f / delta), playing->true_filter_cutoff, playing->true_filter_resonance); it_filter(cr ? cr[1] : NULL, &playing->filter_state[1], samples[0 /*output*/] + 1, pos, samples_to_filter[0] + 1, size_rendered, 2, (int)(65536.0f / delta), playing->true_filter_cutoff, playing->true_filter_resonance); } else { it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[0 /*output*/], pos, samples_to_filter[0], size_rendered, 1, (int)(65536.0f / delta), playing->true_filter_cutoff, playing->true_filter_resonance); } // FIXME: filtering is not prevented by low left_to_mix! // FIXME: change 'warning' to 'FIXME' everywhere } } else { it_reset_filter_state(&playing->filter_state[0]); it_reset_filter_state(&playing->filter_state[1]); render_playing(sigrenderer, playing, volume, delta, note_delta, pos, size, samples /*&samples[output]*/, 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_playing(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_playing(sigrenderer->playing[i]); sigrenderer->playing[i] = NULL; } } } } static void render_surround(DUMB_IT_SIGRENDERER *sigrenderer, float volume, float delta, long pos, long size, sample_t **samples) { int i; int n_to_mix = 0, n_to_mix_surround = 0; IT_TO_MIX to_mix[DUMB_IT_TOTAL_CHANNELS]; IT_TO_MIX to_mix_surround[DUMB_IT_TOTAL_CHANNELS]; int left_to_mix = dumb_it_max_to_mix; int saved_channels = sigrenderer->n_channels; sample_t **samples_to_filter = NULL; DUMB_CLICK_REMOVER **saved_cr = sigrenderer->click_remover; // int max_output = sigrenderer->max_output; for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { if (sigrenderer->channel[i].playing && !(sigrenderer->channel[i].playing->flags & IT_PLAYING_DEAD)) { IT_PLAYING *playing = sigrenderer->channel[i].playing; IT_TO_MIX *_to_mix = IT_IS_SURROUND_SHIFTED(playing->pan) ? to_mix_surround + n_to_mix_surround++ : to_mix + n_to_mix++; _to_mix->playing = playing; _to_mix->volume = volume == 0 ? 0 : calculate_volume(sigrenderer, playing, volume); } } for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (sigrenderer ->playing[i]) { /* Won't be dead; it would have been freed. */ IT_PLAYING *playing = sigrenderer->playing[i]; IT_TO_MIX *_to_mix = IT_IS_SURROUND_SHIFTED(playing->pan) ? to_mix_surround + n_to_mix_surround++ : to_mix + n_to_mix++; _to_mix->playing = playing; _to_mix->volume = volume == 0 ? 0 : calculate_volume(sigrenderer, playing, volume); } } if (volume != 0) { qsort(to_mix, n_to_mix, sizeof(IT_TO_MIX), &it_to_mix_compare); qsort(to_mix_surround, n_to_mix_surround, sizeof(IT_TO_MIX), &it_to_mix_compare); } sigrenderer->n_channels = 2; for (i = 0; i < n_to_mix; i++) { IT_PLAYING *playing = to_mix[i].playing; float note_delta = delta * playing->delta; int cutoff = playing->filter_cutoff << IT_ENVELOPE_SHIFT; // int output = min( playing->output, max_output ); apply_pitch_modifications(sigrenderer->sigdata, playing, ¬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 (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, delta, 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, volume, delta, note_delta, 0, size, samples_to_filter, 1, &left_to_mix); sigrenderer->click_remover = cr; it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[0 /*output*/], pos, samples_to_filter[0], size_rendered, 2, (int)(65536.0f / delta), playing->true_filter_cutoff, playing->true_filter_resonance); it_filter(cr ? cr[1] : NULL, &playing->filter_state[1], samples[0 /*output*/] + 1, pos, samples_to_filter[0] + 1, size_rendered, 2, (int)(65536.0f / delta), playing->true_filter_cutoff, playing->true_filter_resonance); } } else { it_reset_filter_state(&playing->filter_state[0]); it_reset_filter_state(&playing->filter_state[1]); render_playing(sigrenderer, playing, volume, delta, note_delta, pos, size, samples /*&samples[output]*/, 0, &left_to_mix); } } sigrenderer->n_channels = 1; sigrenderer->click_remover = saved_cr ? saved_cr + 2 : 0; for (i = 0; i < n_to_mix_surround; i++) { IT_PLAYING *playing = to_mix_surround[i].playing; float note_delta = delta * playing->delta; int cutoff = playing->filter_cutoff << IT_ENVELOPE_SHIFT; // int output = min( playing->output, max_output ); apply_pitch_modifications(sigrenderer->sigdata, playing, ¬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 (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, delta, 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], size + 1); sigrenderer->click_remover = NULL; size_rendered = render_playing( sigrenderer, playing, volume, delta, note_delta, 0, size, samples_to_filter, 1, &left_to_mix); sigrenderer->click_remover = cr; it_filter(cr ? cr[0] : NULL, &playing->filter_state[0], samples[1 /*output*/], pos, samples_to_filter[0], size_rendered, 1, (int)(65536.0f / delta), playing->true_filter_cutoff, playing->true_filter_resonance); // FIXME: filtering is not prevented by low left_to_mix! // FIXME: change 'warning' to 'FIXME' everywhere } } else { it_reset_filter_state(&playing->filter_state[0]); it_reset_filter_state(&playing->filter_state[1]); render_playing(sigrenderer, playing, volume, delta, note_delta, pos, size, &samples[1], 0, &left_to_mix); } } sigrenderer->n_channels = saved_channels; sigrenderer->click_remover = saved_cr; 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_playing(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_playing(sigrenderer->playing[i]); sigrenderer->playing[i] = NULL; } } } } static void render(DUMB_IT_SIGRENDERER *sigrenderer, float volume, float delta, long pos, long size, sample_t **samples) { if (size == 0) return; if (sigrenderer->n_channels == 1 || sigrenderer->n_channels == 2) render_normal(sigrenderer, volume, delta, pos, size, samples); else if (sigrenderer->n_channels == 3) render_surround(sigrenderer, volume, delta, pos, size, samples); } static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_channels, int startorder, IT_CALLBACKS *callbacks, DUMB_CLICK_REMOVER **cr) { DUMB_IT_SIGRENDERER *sigrenderer; int i; if (startorder > sigdata->n_orders) { free(callbacks); dumb_destroy_click_remover_array(n_channels, cr); return NULL; } sigrenderer = malloc(sizeof(*sigrenderer)); if (!sigrenderer) { free(callbacks); dumb_destroy_click_remover_array(n_channels, cr); return NULL; } sigrenderer->callbacks = callbacks; sigrenderer->click_remover = cr; sigrenderer->sigdata = sigdata; sigrenderer->n_channels = n_channels; sigrenderer->resampling_quality = dumb_resampling_quality; sigrenderer->ramp_style = DUMB_IT_RAMP_FULL; sigrenderer->globalvolume = sigdata->global_volume; sigrenderer->tempo = sigdata->tempo; for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { IT_CHANNEL *channel = &sigrenderer->channel[i]; #if IT_CHANNEL_MUTED != 1 #error this is wrong #endif channel->flags = sigdata->channel_pan[i] >> 7; channel->volume = (sigdata->flags & IT_WAS_AN_XM) ? 0 : 64; channel->pan = sigdata->channel_pan[i] & 0x7F; channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; channel->channelvolume = sigdata->channel_volume[i]; channel->instrument = 0; channel->sample = 0; channel->note = IT_NOTE_OFF; channel->SFmacro = 0; channel->filter_cutoff = 127; channel->filter_resonance = 0; channel->new_note_action = 0xFF; channel->xm_retrig = 0; channel->retrig_tick = 0; channel->tremor_time = 0; channel->vibrato_waveform = 0; channel->tremolo_waveform = 0; channel->panbrello_waveform = 0; channel->glissando = 0; channel->toneslide = 0; channel->ptm_toneslide = 0; channel->ptm_last_toneslide = 0; channel->okt_toneslide = 0; channel->midi_state = 0; channel->lastvolslide = 0; channel->lastDKL = 0; channel->lastEF = 0; channel->lastG = 0; channel->lastHspeed = 0; channel->lastHdepth = 0; channel->lastRspeed = 0; channel->lastRdepth = 0; channel->lastYspeed = 0; channel->lastYdepth = 0; channel->lastI = 0; channel->lastJ = 0; channel->lastN = 0; channel->lastO = 0; channel->high_offset = 0; channel->lastP = 0; channel->lastQ = 0; channel->lastS = 0; channel->pat_loop_row = 0; channel->pat_loop_count = 0; channel->pat_loop_end_row = 0; channel->lastW = 0; channel->xm_lastE1 = 0; channel->xm_lastE2 = 0; channel->xm_lastEA = 0; channel->xm_lastEB = 0; channel->xm_lastX1 = 0; channel->xm_lastX2 = 0; channel->inv_loop_delay = 0; channel->inv_loop_speed = 0; channel->inv_loop_offset = 0; channel->playing = NULL; channel->key_off_count = 0; channel->note_cut_count = 0; channel->note_delay_count = 0; channel->note_delay_entry = 0; #ifdef BIT_ARRAY_BULLSHIT channel->played_patjump = NULL; channel->played_patjump_order = 0xFFFE; #endif // channel->output = 0; } if (sigdata->flags & IT_WAS_A_669) reset_effects(sigrenderer); for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) sigrenderer->playing[i] = NULL; sigrenderer->speed = sigdata->speed; sigrenderer->processrow = 0xFFFE; sigrenderer->n_rows = 0; sigrenderer->breakrow = 0; sigrenderer->rowcount = 1; sigrenderer->order = startorder; /* meh! if (startorder > 0) { int n; for (n = startorder - 1; n >= 0; n--) { if (sigdata->order[n] > sigdata->n_patterns) { sigrenderer->restart_position = n + 1; break; } } } */ if (startorder > 0) { sigrenderer->restart_position = startorder; } else { sigrenderer->restart_position = sigdata->restart_position; } sigrenderer->row = 0; sigrenderer->processorder = startorder - 1; sigrenderer->tick = 1; #ifdef BIT_ARRAY_BULLSHIT sigrenderer->played = bit_array_create(sigdata->n_orders * 256); sigrenderer->looped = 0; sigrenderer->time_played = 0; sigrenderer->row_timekeeper = timekeeping_array_create(sigdata->n_orders * 256); #endif { 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; #ifdef BIT_ARRAY_BULLSHIT /* Fix for played order detection for songs which have skips at the * start of the orders list */ for (n = 0; n < 256; n++) { bit_array_set(sigrenderer->played, order * 256 + n); timekeeping_array_push(sigrenderer->row_timekeeper, order * 256 + n, 0); timekeeping_array_bump(sigrenderer->row_timekeeper, order * 256 + n); } #endif } /* 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; sigrenderer->gvz_time = 0; sigrenderer->gvz_sub_time = 0; // sigrenderer->max_output = 0; if (!(sigdata->flags & IT_WAS_PROCESSED)) { if (dumb_it_add_lpc(sigdata) < 0) { _dumb_it_end_sigrenderer(sigrenderer); return NULL; } sigdata->flags |= IT_WAS_PROCESSED; } return sigrenderer; } void dumb_it_set_resampling_quality(DUMB_IT_SIGRENDERER *sigrenderer, int quality) { if (sigrenderer && quality >= 0 && quality < DUMB_RQ_N_LEVELS) { int i; sigrenderer->resampling_quality = quality; for (i = 0; i < DUMB_IT_N_CHANNELS; i++) { if (sigrenderer->channel[i].playing) { IT_PLAYING *playing = sigrenderer->channel[i].playing; playing->resampling_quality = quality; playing->resampler.quality = quality; resampler_set_quality(playing->resampler.fir_resampler[0], quality); resampler_set_quality(playing->resampler.fir_resampler[1], quality); } } for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { if (sigrenderer->playing[i]) { IT_PLAYING *playing = sigrenderer->playing[i]; playing->resampling_quality = quality; playing->resampler.quality = quality; resampler_set_quality(playing->resampler.fir_resampler[0], quality); resampler_set_quality(playing->resampler.fir_resampler[1], quality); } } } } void dumb_it_set_ramp_style(DUMB_IT_SIGRENDERER *sigrenderer, int ramp_style) { if (sigrenderer && ramp_style >= 0 && ramp_style <= 2) { sigrenderer->ramp_style = ramp_style; } } void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data) { if (sigrenderer) { sigrenderer->callbacks->loop = callback; sigrenderer->callbacks->loop_data = data; } } void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data) { if (sigrenderer) { sigrenderer->callbacks->xm_speed_zero = callback; sigrenderer->callbacks->xm_speed_zero_data = data; } } void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data, int channel, unsigned char midi_byte), void *data) { if (sigrenderer) { sigrenderer->callbacks->midi = callback; sigrenderer->callbacks->midi_data = data; } } void dumb_it_set_global_volume_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data) { if (sigrenderer) { sigrenderer->callbacks->global_volume_zero = callback; sigrenderer->callbacks->global_volume_zero_data = data; } } static IT_CALLBACKS *create_callbacks(void) { IT_CALLBACKS *callbacks = malloc(sizeof(*callbacks)); if (!callbacks) return NULL; callbacks->loop = NULL; callbacks->xm_speed_zero = NULL; callbacks->midi = NULL; callbacks->global_volume_zero = NULL; return callbacks; } static DUMB_IT_SIGRENDERER *dumb_it_init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_channels, int startorder) { IT_CALLBACKS *callbacks; if (!sigdata) return NULL; callbacks = create_callbacks(); if (!callbacks) return NULL; return init_sigrenderer(sigdata, n_channels, startorder, callbacks, dumb_create_click_remover_array(n_channels)); } DUH_SIGRENDERER *dumb_it_start_at_order(DUH *duh, int n_channels, int startorder) { DUMB_IT_SIGDATA *itsd = duh_get_it_sigdata(duh); DUMB_IT_SIGRENDERER *itsr = dumb_it_init_sigrenderer(itsd, n_channels, startorder); /*duh->length = dumb_it_build_checkpoints(itsd, startorder);*/ return duh_encapsulate_it_sigrenderer(itsr, n_channels, 0); } static sigrenderer_t *it_start_sigrenderer(DUH *duh, sigdata_t *vsigdata, int n_channels, long pos) { DUMB_IT_SIGDATA *sigdata = vsigdata; DUMB_IT_SIGRENDERER *sigrenderer; (void)duh; { IT_CALLBACKS *callbacks = create_callbacks(); if (!callbacks) return NULL; if (sigdata->checkpoint) { IT_CHECKPOINT *checkpoint = sigdata->checkpoint; while (checkpoint->next && checkpoint->next->time < pos) checkpoint = checkpoint->next; sigrenderer = dup_sigrenderer(checkpoint->sigrenderer, n_channels, callbacks); if (!sigrenderer) return NULL; sigrenderer->click_remover = dumb_create_click_remover_array(n_channels); pos -= checkpoint->time; } else { sigrenderer = init_sigrenderer(sigdata, n_channels, 0, callbacks, dumb_create_click_remover_array(n_channels)); if (!sigrenderer) return NULL; } } while (pos > 0 && pos >= sigrenderer->time_left) { render(sigrenderer, 0, 1.0f, 0, sigrenderer->time_left, NULL); #ifdef BIT_ARRAY_BULLSHIT sigrenderer->time_played += (LONG_LONG)sigrenderer->time_left << 16; #endif 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; #ifdef BIT_ARRAY_BULLSHIT sigrenderer->time_played += (LONG_LONG)pos << 16; #endif 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; int ret; LONG_LONG t; if (sigrenderer->order < 0) return 0; // problematic if (!sigrenderer->tempo) return 0; // also 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); #ifdef BIT_ARRAY_BULLSHIT sigrenderer->time_played += (LONG_LONG)todo * dt; #endif ret = process_tick(sigrenderer); if (ret) { sigrenderer->order = -1; sigrenderer->row = -1; } #ifdef BIT_ARRAY_BULLSHIT if (sigrenderer->looped == 1) { sigrenderer->looped = -1; size = 0; timekeeping_array_reset(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row); sigrenderer->time_played = timekeeping_array_get_item( sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row); break; } #endif if (ret) { 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); #ifdef BIT_ARRAY_BULLSHIT sigrenderer->time_played += (LONG_LONG)size * dt; #endif 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_playing(sigrenderer->channel[i].playing); #ifdef BIT_ARRAY_BULLSHIT bit_array_destroy(sigrenderer->channel[i].played_patjump); #endif } for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) if (sigrenderer->playing[i]) free_playing(sigrenderer->playing[i]); dumb_destroy_click_remover_array(sigrenderer->n_channels, sigrenderer->click_remover); if (sigrenderer->callbacks) free(sigrenderer->callbacks); #ifdef BIT_ARRAY_BULLSHIT bit_array_destroy(sigrenderer->played); timekeeping_array_destroy(sigrenderer->row_timekeeper); #endif free(vsigrenderer); } } #ifdef BIT_ARRAY_BULLSHIT static long it_sigrenderer_get_position(sigrenderer_t *vsigrenderer) { DUMB_IT_SIGRENDERER *sigrenderer = (DUMB_IT_SIGRENDERER *)vsigrenderer; return (long)(sigrenderer->time_played >> 16); } #endif DUH_SIGTYPE_DESC _dumb_sigtype_it = {SIGTYPE_IT, NULL, &it_start_sigrenderer, NULL, &it_sigrenderer_get_samples, &it_sigrenderer_get_current_sample, #ifdef BIT_ARRAY_BULLSHIT &it_sigrenderer_get_position, #else NULL, #endif &_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 = (int)(playing->channel - sr->channel); state->sample = playing->sampnum; state->volume = calculate_volume(sr, playing, 1.0f); t = apply_pan_envelope(playing); state->pan = (unsigned char)((t + 128) >> IT_ENVELOPE_SHIFT); state->subpan = (signed char)t; delta = playing->delta * 65536.0f; t = playing->filter_cutoff << IT_ENVELOPE_SHIFT; apply_pitch_modifications(sr->sigdata, playing, &delta, &t); state->freq = (int)delta; if (t == 127 << IT_ENVELOPE_SHIFT && playing->filter_resonance == 0) { state->filter_resonance = playing->true_filter_resonance; t = playing->true_filter_cutoff; } else state->filter_resonance = playing->filter_resonance; state->filter_cutoff = (unsigned char)(t >> 8); state->filter_subcutoff = (unsigned char)t; } int dumb_it_callback_terminate(void *data) { (void)data; return 1; } int dumb_it_callback_midi_block(void *data, int channel, unsigned char midi_byte) { (void)data; (void)channel; (void)midi_byte; return 1; } #define IT_CHECKPOINT_INTERVAL (30 * 65536) /* Half a minute */ #define FUCKIT_THRESHOLD \ (120 * 60 * 65536) /* two hours? probably a pattern loop mess... */ /* Returns the length of the module, up until it first loops. */ long dumb_it_build_checkpoints(DUMB_IT_SIGDATA *sigdata, int startorder) { IT_CHECKPOINT *checkpoint; if (!sigdata) return 0; checkpoint = sigdata->checkpoint; while (checkpoint) { IT_CHECKPOINT *next = checkpoint->next; _dumb_it_end_sigrenderer(checkpoint->sigrenderer); free(checkpoint); checkpoint = next; } sigdata->checkpoint = NULL; checkpoint = malloc(sizeof(*checkpoint)); if (!checkpoint) return 0; checkpoint->time = 0; checkpoint->sigrenderer = dumb_it_init_sigrenderer(sigdata, 0, startorder); if (!checkpoint->sigrenderer) { free(checkpoint); return 0; } checkpoint->sigrenderer->callbacks->loop = &dumb_it_callback_terminate; checkpoint->sigrenderer->callbacks->xm_speed_zero = &dumb_it_callback_terminate; checkpoint->sigrenderer->callbacks->global_volume_zero = &dumb_it_callback_terminate; if (sigdata->checkpoint) { IT_CHECKPOINT *checkpoint = sigdata->checkpoint; while (checkpoint) { IT_CHECKPOINT *next = checkpoint->next; _dumb_it_end_sigrenderer(checkpoint->sigrenderer); free(checkpoint); checkpoint = next; } } sigdata->checkpoint = checkpoint; for (;;) { long l; DUMB_IT_SIGRENDERER *sigrenderer = dup_sigrenderer( checkpoint->sigrenderer, 0, checkpoint->sigrenderer->callbacks); checkpoint->sigrenderer->callbacks = NULL; if (!sigrenderer) { checkpoint->next = NULL; return checkpoint->time; } l = it_sigrenderer_get_samples(sigrenderer, 0, 1.0f, IT_CHECKPOINT_INTERVAL, NULL); if (l < IT_CHECKPOINT_INTERVAL) { _dumb_it_end_sigrenderer(sigrenderer); checkpoint->next = NULL; return checkpoint->time + l; } checkpoint->next = malloc(sizeof(*checkpoint->next)); if (!checkpoint->next) { _dumb_it_end_sigrenderer(sigrenderer); return checkpoint->time + IT_CHECKPOINT_INTERVAL; } checkpoint->next->time = checkpoint->time + IT_CHECKPOINT_INTERVAL; checkpoint = checkpoint->next; checkpoint->sigrenderer = sigrenderer; if (checkpoint->time >= FUCKIT_THRESHOLD) { checkpoint->next = NULL; return 0; } } } void dumb_it_do_initial_runthrough(DUH *duh) { if (duh) { DUMB_IT_SIGDATA *sigdata = duh_get_it_sigdata(duh); if (sigdata) duh_set_length(duh, dumb_it_build_checkpoints(sigdata, 0)); } } static int is_pattern_silent(IT_PATTERN *pattern, int order) { int ret = 1; IT_ENTRY *entry, *end; if (!pattern || !pattern->n_rows || !pattern->n_entries || !pattern->entry) return 2; if (pattern->n_entries == pattern->n_rows) { int n; entry = pattern->entry; for (n = 0; n < pattern->n_entries; ++n, ++entry) { if (!IT_IS_END_ROW(entry)) break; } if (n == pattern->n_entries) return 2; // broken? } entry = pattern->entry; end = entry + pattern->n_entries; while (entry < end) { if (!IT_IS_END_ROW(entry)) { if (entry->mask & (IT_ENTRY_INSTRUMENT | IT_ENTRY_VOLPAN)) return 0; if (entry->mask & IT_ENTRY_NOTE && entry->note < 120) return 0; if (entry->mask & IT_ENTRY_EFFECT) { switch (entry->effect) { case IT_SET_GLOBAL_VOLUME: if (entry->effectvalue) return 0; break; case IT_SET_SPEED: if (entry->effectvalue > 64) ret++; break; case IT_SET_SONG_TEMPO: case IT_XM_KEY_OFF: break; case IT_JUMP_TO_ORDER: if (entry->effectvalue != order) return 0; break; case IT_S: switch (entry->effectvalue >> 4) { case 0: // meh bastard if (entry->effectvalue != 0) return 0; break; case IT_S_FINE_PATTERN_DELAY: case IT_S_PATTERN_LOOP: case IT_S_PATTERN_DELAY: ret++; break; case IT_S7: if ((entry->effectvalue & 15) > 2) return 0; break; default: return 0; } break; // clever idiot with his S L O W crap; do nothing case IT_VOLSLIDE_TONEPORTA: case IT_SET_SAMPLE_OFFSET: case IT_GLOBAL_VOLUME_SLIDE: if (entry->effectvalue != 0) return 0; break; // genius also uses this instead of jump to order by mistake, // meh, and it's bloody BCD case IT_BREAK_TO_ROW: if (((entry->effectvalue >> 4) * 10 + (entry->effectvalue & 15)) != order) return 0; break; default: return 0; } } } entry++; } return ret; } int dumb_it_trim_silent_patterns(DUH *duh) { int n; DUMB_IT_SIGDATA *sigdata; if (!duh) return -1; sigdata = duh_get_it_sigdata(duh); if (!sigdata || !sigdata->order || !sigdata->pattern) return -1; for (n = 0; n < sigdata->n_orders; n++) { int p = sigdata->order[n]; if (p < sigdata->n_patterns) { IT_PATTERN *pattern = &sigdata->pattern[p]; if (is_pattern_silent(pattern, n) > 1) { pattern->n_rows = 1; pattern->n_entries = 0; if (pattern->entry) { free(pattern->entry); pattern->entry = NULL; } } else break; } } if (n == sigdata->n_orders) return -1; for (n = sigdata->n_orders - 1; n >= 0; n--) { int p = sigdata->order[n]; if (p < sigdata->n_patterns) { IT_PATTERN *pattern = &sigdata->pattern[p]; if (is_pattern_silent(pattern, n) > 1) { pattern->n_rows = 1; pattern->n_entries = 0; if (pattern->entry) { free(pattern->entry); pattern->entry = NULL; } } else break; } } if (n < 0) return -1; /*duh->length = dumb_it_build_checkpoints(sigdata, 0);*/ return 0; } int dumb_it_scan_for_playable_orders(DUMB_IT_SIGDATA *sigdata, dumb_scan_callback callback, void *callback_data) { int n; long length; void *ba_played; DUMB_IT_SIGRENDERER *sigrenderer; if (!sigdata->n_orders || !sigdata->order) return -1; ba_played = bit_array_create(sigdata->n_orders * 256); if (!ba_played) return -1; /* Skip the first order, it should always be played */ for (n = 1; n < sigdata->n_orders; n++) { if ((sigdata->order[n] >= sigdata->n_patterns) || (is_pattern_silent(&sigdata->pattern[sigdata->order[n]], n) > 1)) bit_array_set(ba_played, n * 256); } for (;;) { for (n = 0; n < sigdata->n_orders; n++) { if (!bit_array_test_range(ba_played, n * 256, 256)) break; } if (n == sigdata->n_orders) break; sigrenderer = dumb_it_init_sigrenderer(sigdata, 0, n); if (!sigrenderer) { bit_array_destroy(ba_played); return -1; } sigrenderer->callbacks->loop = &dumb_it_callback_terminate; sigrenderer->callbacks->xm_speed_zero = &dumb_it_callback_terminate; sigrenderer->callbacks->global_volume_zero = &dumb_it_callback_terminate; length = 0; for (;;) { long l; l = it_sigrenderer_get_samples(sigrenderer, 0, 1.0f, IT_CHECKPOINT_INTERVAL, NULL); length += l; if (l < IT_CHECKPOINT_INTERVAL || length >= FUCKIT_THRESHOLD) { /* SONG OVA! */ break; } } if ((*callback)(callback_data, n, length) < 0) return -1; bit_array_merge(ba_played, sigrenderer->played, 0); _dumb_it_end_sigrenderer(sigrenderer); } bit_array_destroy(ba_played); return 0; }