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