vkdoom_m/dumb/src/it/itrender.c
Randy Heit 01f59fa85f - Added an alternate module replay engine that uses foo_dumb's replayer, a
heavily customized version of DUMB (Dynamic Universal Music Bibliotheque).
  It has been slightly modified by me:
  * Added support for Ogg Vorbis-compressed samples in XM files ala FMOD.
  * Removed excessive mallocs from the replay core.
  * Rerolled the loops in resample.c. Unrolling them made the object file
    ~250k large while providing little benefit. Even at ~100k, I think it's
    still larger than it ought to be, but I'll live with it for now.
  Other than that, it's essentially the same thing you'd hear in foobar2000,
  minus some subsong detection features. Release builds of the library look
  like they might even be slightly faster than FMOD, which is a plus.
- Fixed: Timidity::font_add() did not release the file reader it created.
- Fixed: The SF2 loader did not free the sample headers in its destructor.


SVN r995 (trunk)
2008-05-29 23:33:07 +00:00

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