blob: a635039babe84ff6952de000f4f80ca50b0e6d1d [file] [log] [blame]
/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
* | | | | | | || ||\ /| |
* | | | | | | || || \/ | | ' ' '
* | | | | | | || || | | . .
* | |_/ / \ \__// || | |
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
* / \
* / . \
* xmeffect.c - Code for converting MOD/XM / / \ \
* effects to IT effects. | < / \_
* | \/ /\ /
* By Julien Cugniere. Ripped out of readxm.c \_ / > /
* by entheh. | \ / /
* | ' /
* \__/
*/
#include <stdlib.h>
#include <string.h>
#include "dumb.h"
#include "internal/it.h"
#if 0
unsigned char **_dumb_malloc2(int w, int h)
{
unsigned char **line = malloc(h * sizeof(*line));
int i;
if (!line) return NULL;
line[0] = malloc(w * h * sizeof(*line[0]));
if (!line[0]) {
free(line);
return NULL;
}
for (i = 1; i < h; i++)
line[i] = line[i-1] + w;
memset(line[0], 0, w*h);
return line;
}
void _dumb_free2(unsigned char **line)
{
if (line) {
if (line[0])
free(line[0]);
free(line);
}
}
/* Effects having a memory. 2 means that the two parts of the effectvalue
* should be handled separately.
*/
static const char xm_has_memory[] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D (E) F G H K L P R T (X) */
0, 1, 1, 1, 2, 1, 1, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
/* E0 E1 E2 E3 E4 E5 E6 E7 E9 EA EB EC ED EE X1 X2 */
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#endif
/* Effects marked with 'special' are handled specifically in itrender.c */
void _dumb_it_xm_convert_effect(int effect, int value, IT_ENTRY *entry)
{
#ifdef SIMULATOR
const int log = 0;
#endif
if ((!effect && !value) || (effect >= XM_N_EFFECTS))
return;
#ifdef SIMULATOR
if (log) DEBUGF("%c%02X", (effect<10)?('0'+effect):('A'+effect-10), value);
#endif
/* Linearisation of the effect number... */
if (effect == XM_E) {
effect = EBASE + HIGH(value);
value = LOW(value);
} else if (effect == XM_X) {
effect = XBASE + HIGH(value);
value = LOW(value);
}
#ifdef SIMULATOR
if (log) DEBUGF(" - %2d %02X", effect, value);
#endif
#if 0 // This should be handled in itrender.c!
/* update effect memory */
switch (xm_has_memory[effect]) {
case 1:
if (!value)
value = memory[entry->channel][effect];
else
memory[entry->channel][effect] = value;
break;
case 2:
if (!HIGH(value))
SET_HIGH(value, HIGH(memory[entry->channel][effect]));
else
SET_HIGH(memory[entry->channel][effect], HIGH(value));
if (!LOW(value))
SET_LOW(value, LOW(memory[entry->channel][effect]));
else
SET_LOW(memory[entry->channel][effect], LOW(value));
break;
}
#endif
/* convert effect */
entry->mask |= IT_ENTRY_EFFECT;
switch (effect) {
case XM_APPREGIO: effect = IT_ARPEGGIO; break;
case XM_VIBRATO: effect = IT_VIBRATO; break;
case XM_TONE_PORTAMENTO: effect = IT_TONE_PORTAMENTO; break; /** TODO: glissando control */
case XM_TREMOLO: effect = IT_TREMOLO; break;
case XM_SET_PANNING: effect = IT_SET_PANNING; break;
case XM_SAMPLE_OFFSET: effect = IT_SET_SAMPLE_OFFSET; break;
case XM_POSITION_JUMP: effect = IT_JUMP_TO_ORDER; break;
case XM_MULTI_RETRIG: effect = IT_RETRIGGER_NOTE; break;
case XM_TREMOR: effect = IT_TREMOR; break;
case XM_PORTAMENTO_UP: effect = IT_XM_PORTAMENTO_UP; break;
case XM_PORTAMENTO_DOWN: effect = IT_XM_PORTAMENTO_DOWN; break;
case XM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break; /* special */
case XM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break; /* special */
case XM_VOLSLIDE_VIBRATO: effect = IT_VOLSLIDE_VIBRATO; break; /* special */
case XM_PATTERN_BREAK:
effect = IT_BREAK_TO_ROW;
value = BCD_TO_NORMAL(value);
break;
case XM_VOLUME_SLIDE: /* special */
effect = IT_VOLUME_SLIDE;
value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
break;
case XM_PANNING_SLIDE:
effect = IT_PANNING_SLIDE;
value = HIGH(value) ? EFFECT_VALUE(0, HIGH(value)) : EFFECT_VALUE(LOW(value), 0);
break;
case XM_GLOBAL_VOLUME_SLIDE: /* special */
effect = IT_GLOBAL_VOLUME_SLIDE;
value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
break;
case XM_SET_TEMPO_BPM:
effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
break;
case XM_SET_GLOBAL_VOLUME:
effect = IT_SET_GLOBAL_VOLUME;
value *= 2;
break;
case XM_KEY_OFF:
/** WARNING: In FT2, the value seems to do something... Oh well,
* this is undocumented anyway!
*/
entry->mask &= ~IT_ENTRY_EFFECT;
entry->mask |= IT_ENTRY_NOTE;
entry->note = IT_NOTE_OFF;
break;
case EBASE+XM_E_SET_FILTER: effect = SBASE+IT_S_SET_FILTER; break;
case EBASE+XM_E_SET_GLISSANDO_CONTROL: effect = SBASE+IT_S_SET_GLISSANDO_CONTROL; break; /** TODO */
case EBASE+XM_E_SET_FINETUNE: effect = SBASE+IT_S_FINETUNE; break; /** TODO */
case EBASE+XM_E_SET_LOOP: effect = SBASE+IT_S_PATTERN_LOOP; break;
case EBASE+XM_E_NOTE_CUT: effect = SBASE+IT_S_DELAYED_NOTE_CUT; break;
case EBASE+XM_E_NOTE_DELAY: effect = SBASE+IT_S_NOTE_DELAY; break;
case EBASE+XM_E_PATTERN_DELAY: effect = SBASE+IT_S_PATTERN_DELAY; break;
case EBASE+XM_E_FINE_VOLSLIDE_UP: effect = IT_XM_FINE_VOLSLIDE_UP; break;
case EBASE+XM_E_FINE_VOLSLIDE_DOWN: effect = IT_XM_FINE_VOLSLIDE_DOWN; break;
case EBASE + XM_E_FINE_PORTA_UP:
effect = IT_PORTAMENTO_UP;
value = EFFECT_VALUE(0xF, value);
break;
case EBASE + XM_E_FINE_PORTA_DOWN:
effect = IT_PORTAMENTO_DOWN;
value = EFFECT_VALUE(0xF, value);
break;
case EBASE + XM_E_RETRIG_NOTE:
effect = IT_XM_RETRIGGER_NOTE;
value = EFFECT_VALUE(0, value);
break;
case EBASE + XM_E_SET_VIBRATO_CONTROL:
effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM;
value &= ~4; /** TODO: value&4 -> don't retrig wave */
break;
case EBASE + XM_E_SET_TREMOLO_CONTROL:
effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM;
value &= ~4; /** TODO: value&4 -> don't retrig wave */
break;
case XBASE + XM_X_EXTRAFINE_PORTA_UP:
effect = IT_PORTAMENTO_UP;
value = EFFECT_VALUE(0xE, value);
break;
case XBASE + XM_X_EXTRAFINE_PORTA_DOWN:
effect = IT_PORTAMENTO_DOWN;
value = EFFECT_VALUE(0xE, value);
break;
default:
/* user effect (often used in demos for synchronisation) */
entry->mask &= ~IT_ENTRY_EFFECT;
}
#ifdef SIMULATOR
if (log) DEBUGF(" - %2d %02X", effect, value);
#endif
/* Inverse linearisation... */
if (effect >= SBASE && effect < SBASE+16) {
value = EFFECT_VALUE(effect-SBASE, value);
effect = IT_S;
}
#ifdef SIMULATOR
if (log) DEBUGF(" - %c%02X\n", 'A'+effect-1, value);
#endif
entry->effect = effect;
entry->effectvalue = value;
}