1 /*  _______         ____    __         ___    ___
2  * \    _  \       \    /  \  /       \   \  /   /       '   '  '
3  *  |  | \  \       |  |    ||         |   \/   |         .      .
4  *  |  |  |  |      |  |    ||         ||\  /|  |
5  *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
6  *  |  |  |  |      |  |    ||         ||    |  |         .      .
7  *  |  |_/  /        \  \__//          ||    |  |
8  * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
9  *                                                      /  \
10  *                                                     / .  \
11  * xmeffect.c - Code for converting MOD/XM            / / \  \
12  *              effects to IT effects.               | <  /   \_
13  *                                                   |  \/ /\   /
14  * By Julien Cugniere. Ripped out of readxm.c         \_  /  > /
15  * by entheh.                                           | \ / /
16  *                                                      |  ' /
17  *                                                       \__/
18  */
19 
20 
21 
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "dumb.h"
26 #include "internal/it.h"
27 
28 #if 0
29 unsigned char **_dumb_malloc2(int w, int h)
30 {
31 	unsigned char **line =  malloc(h * sizeof(*line));
32 	int i;
33 	if (!line) return NULL;
34 
35 	line[0] = malloc(w * h * sizeof(*line[0]));
36 	if (!line[0]) {
37 		free(line);
38 		return NULL;
39 	}
40 
41 	for (i = 1; i < h; i++)
42 		line[i] = line[i-1] + w;
43 
44 	memset(line[0], 0, w*h);
45 
46 	return line;
47 }
48 
49 
50 
51 void _dumb_free2(unsigned char **line)
52 {
53 	if (line) {
54 		if (line[0])
55 			free(line[0]);
56 		free(line);
57 	}
58 }
59 
60 
61 
62 /* Effects having a memory. 2 means that the two parts of the effectvalue
63  * should be handled separately.
64  */
65 static const char xm_has_memory[] = {
66 /*	0  1  2  3  4  5  6  7  8  9  A  B  C  D (E) F  G  H        K  L           P     R     T          (X) */
67 	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,
68 
69 /*  E0 E1 E2 E3 E4 E5 E6 E7    E9 EA EB EC ED EE         X1 X2 */
70 	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
71 };
72 #endif
73 
74 
75 
76 /* Effects marked with 'special' are handled specifically in itrender.c */
_dumb_it_xm_convert_effect(int effect,int value,IT_ENTRY * entry,int mod)77 void _dumb_it_xm_convert_effect(int effect, int value, IT_ENTRY *entry, int mod)
78 {
79 const int log = 0;
80 
81 	if ((!effect && !value) || (effect >= XM_N_EFFECTS))
82 		return;
83 
84 if (log) printf("%c%02X", (effect<10)?('0'+effect):('A'+effect-10), value);
85 
86 	/* Linearisation of the effect number... */
87 	if (effect == XM_E) {
88 		effect = EBASE + HIGH(value);
89 		value = LOW(value);
90 	} else if (effect == XM_X) {
91 		effect = XBASE + HIGH(value);
92 		value = LOW(value);
93 	}
94 
95 if (log) printf(" - %2d %02X", effect, value);
96 
97 #if 0 // This should be handled in itrender.c!
98 	/* update effect memory */
99 	switch (xm_has_memory[effect]) {
100 		case 1:
101 			if (!value)
102 				value = memory[entry->channel][effect];
103 			else
104 				memory[entry->channel][effect] = value;
105 			break;
106 
107 		case 2:
108 			if (!HIGH(value))
109 				SET_HIGH(value, HIGH(memory[entry->channel][effect]));
110 			else
111 				SET_HIGH(memory[entry->channel][effect], HIGH(value));
112 
113 			if (!LOW(value))
114 				SET_LOW(value, LOW(memory[entry->channel][effect]));
115 			else
116 				SET_LOW(memory[entry->channel][effect], LOW(value));
117 			break;
118 	}
119 #endif
120 
121 	/* convert effect */
122 	entry->mask |= IT_ENTRY_EFFECT;
123 	switch (effect) {
124 
125 		case XM_APPREGIO:           effect = IT_ARPEGGIO;           break;
126 		case XM_VIBRATO:            effect = IT_VIBRATO;            break;
127 		case XM_TONE_PORTAMENTO:    effect = IT_TONE_PORTAMENTO;    break;
128 		case XM_TREMOLO:            effect = IT_TREMOLO;            break;
129 		case XM_SET_PANNING:        effect = IT_SET_PANNING;        break;
130 		case XM_SAMPLE_OFFSET:      effect = IT_SET_SAMPLE_OFFSET;  break;
131 		case XM_POSITION_JUMP:      effect = IT_JUMP_TO_ORDER;      break;
132 		case XM_MULTI_RETRIG:       effect = IT_RETRIGGER_NOTE;     break;
133 		case XM_TREMOR:             effect = IT_TREMOR;             break;
134 		case XM_PORTAMENTO_UP:      effect = IT_XM_PORTAMENTO_UP;   break;
135 		case XM_PORTAMENTO_DOWN:    effect = IT_XM_PORTAMENTO_DOWN; break;
136 		case XM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break; /* special */
137 		case XM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break; /* special */
138 		case XM_VOLSLIDE_VIBRATO:   effect = IT_VOLSLIDE_VIBRATO;   break; /* special */
139 
140 		case XM_PATTERN_BREAK:
141 			effect = IT_BREAK_TO_ROW;
142 			value = BCD_TO_NORMAL(value);
143 			if (value > 63) value = 0; /* FT2, maybe ProTracker? */
144 			break;
145 
146 		case XM_VOLUME_SLIDE: /* special */
147 			effect = IT_VOLUME_SLIDE;
148 			value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
149 			break;
150 
151 		case XM_PANNING_SLIDE:
152 			effect = IT_PANNING_SLIDE;
153 			//value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
154 			value = HIGH(value) ? EFFECT_VALUE(0, HIGH(value)) : EFFECT_VALUE(LOW(value), 0);
155 			break;
156 
157 		case XM_GLOBAL_VOLUME_SLIDE: /* special */
158 			effect = IT_GLOBAL_VOLUME_SLIDE;
159 			value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
160 			break;
161 
162 		case XM_SET_TEMPO_BPM:
163 			if (mod) effect = (value <= 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
164 			else effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
165 			break;
166 
167 		case XM_SET_GLOBAL_VOLUME:
168 			effect = IT_SET_GLOBAL_VOLUME;
169 			value *= 2;
170 			if (value > 128) value = 128;
171 			break;
172 
173 		case XM_KEY_OFF:
174 			effect = IT_XM_KEY_OFF;
175 			break;
176 
177 		case XM_SET_ENVELOPE_POSITION:
178 			effect = IT_XM_SET_ENVELOPE_POSITION;
179 			break;
180 
181 		case EBASE+XM_E_SET_FILTER:            effect = SBASE+IT_S_SET_FILTER;            break;
182 		case EBASE+XM_E_SET_GLISSANDO_CONTROL: effect = SBASE+IT_S_SET_GLISSANDO_CONTROL; break; /** TODO */
183 		case EBASE+XM_E_SET_FINETUNE:          effect = SBASE+IT_S_FINETUNE;              break;
184 		case EBASE+XM_E_SET_LOOP:              effect = SBASE+IT_S_PATTERN_LOOP;          break;
185 		case EBASE+XM_E_NOTE_CUT:              effect = SBASE+IT_S_DELAYED_NOTE_CUT;      break;
186 		case EBASE+XM_E_NOTE_DELAY:            effect = SBASE+IT_S_NOTE_DELAY;            break;
187 		case EBASE+XM_E_PATTERN_DELAY:         effect = SBASE+IT_S_PATTERN_DELAY;         break;
188 		case EBASE+XM_E_SET_PANNING:           effect = SBASE+IT_S_SET_PAN;               break;
189 		case EBASE+XM_E_FINE_VOLSLIDE_UP:      effect = IT_XM_FINE_VOLSLIDE_UP;           break;
190 		case EBASE+XM_E_FINE_VOLSLIDE_DOWN:    effect = IT_XM_FINE_VOLSLIDE_DOWN;         break;
191 		case EBASE+XM_E_SET_MIDI_MACRO:        effect = SBASE+IT_S_SET_MIDI_MACRO;        break;
192 
193 		case EBASE + XM_E_FINE_PORTA_UP:
194 			effect = IT_PORTAMENTO_UP;
195 			value = EFFECT_VALUE(0xF, value);
196 			break;
197 
198 		case EBASE + XM_E_FINE_PORTA_DOWN:
199 			effect = IT_PORTAMENTO_DOWN;
200 			value = EFFECT_VALUE(0xF, value);
201 			break;
202 
203 		case EBASE + XM_E_RETRIG_NOTE:
204 			effect = IT_XM_RETRIGGER_NOTE;
205 			value = EFFECT_VALUE(0, value);
206 			break;
207 
208 		case EBASE + XM_E_SET_VIBRATO_CONTROL:
209 			effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM;
210 			value &= ~4;
211 			break;
212 
213 		case EBASE + XM_E_SET_TREMOLO_CONTROL:
214 			effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM;
215 			value &= ~4;
216 			break;
217 
218 		case XBASE + XM_X_EXTRAFINE_PORTA_UP:
219 			effect = IT_PORTAMENTO_UP;
220 			value = EFFECT_VALUE(0xE, value);
221 			break;
222 
223 		case XBASE + XM_X_EXTRAFINE_PORTA_DOWN:
224 			effect = IT_PORTAMENTO_DOWN;
225 			value = EFFECT_VALUE(0xE, value);
226 			break;
227 
228 		default:
229 			/* user effect (often used in demos for synchronisation) */
230 			entry->mask &= ~IT_ENTRY_EFFECT;
231 	}
232 
233 if (log) printf(" - %2d %02X", effect, value);
234 
235 	/* Inverse linearisation... */
236 	if (effect >= SBASE && effect < SBASE+16) {
237 		value = EFFECT_VALUE(effect-SBASE, value);
238 		effect = IT_S;
239 	}
240 
241 if (log) printf(" - %c%02X\n", 'A'+effect-1, value);
242 
243 	entry->effect = effect;
244 	entry->effectvalue = value;
245 }
246