1 /*
2  * Schism Tracker - a cross-platform Impulse Tracker clone
3  * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com>
4  * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org>
5  * copyright (c) 2009 Storlek & Mrs. Brisby
6  * copyright (c) 2010-2012 Storlek
7  * URL: http://schismtracker.org/
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #include "headers.h"
25 #include "fmt.h"
26 
27 /* --------------------------------------------------------------------------------------------------------- */
28 
_mod_period_to_note(int period)29 static int _mod_period_to_note(int period)
30 {
31 	int n;
32 
33 	if (period)
34 		for (n = 0; n <= NOTE_LAST; n++)
35 			if (period >= (32 * period_table[n % 12] >> (n / 12 + 2)))
36 				return n + 1;
37 	return NOTE_NONE;
38 }
39 
mod_import_note(const uint8_t p[4],song_note_t * note)40 void mod_import_note(const uint8_t p[4], song_note_t *note)
41 {
42 	note->note = _mod_period_to_note(((p[0] & 0xf) << 8) + p[1]);
43 	note->instrument = (p[0] & 0xf0) + (p[2] >> 4);
44 	note->voleffect = VOLFX_NONE;
45 	note->volparam = 0;
46 	note->effect = p[2] & 0xf;
47 	note->param = p[3];
48 }
49 
50 /* --------------------------------------------------------------------------------------------------------- */
51 
52 const uint8_t effect_weight[FX_MAX] = {
53 	[FX_PATTERNBREAK]       = 248,
54 	[FX_POSITIONJUMP]       = 240,
55 	[FX_SPEED]              = 232,
56 	[FX_TEMPO]              = 224,
57 	[FX_GLOBALVOLUME]       = 216,
58 	[FX_GLOBALVOLSLIDE]     = 208,
59 	[FX_CHANNELVOLUME]      = 200,
60 	[FX_CHANNELVOLSLIDE]    = 192,
61 	[FX_TONEPORTAVOL]       = 184,
62 	[FX_TONEPORTAMENTO]     = 176,
63 	[FX_ARPEGGIO]           = 168,
64 	[FX_RETRIG]             = 160,
65 	[FX_TREMOR]             = 152,
66 	[FX_OFFSET]             = 144,
67 	[FX_VOLUME]             = 136,
68 	[FX_VIBRATOVOL]         = 128,
69 	[FX_VOLUMESLIDE]        = 120,
70 	[FX_PORTAMENTODOWN]     = 112,
71 	[FX_PORTAMENTOUP]       = 104,
72 	[FX_NOTESLIDEDOWN]      =  96, // IMF Hxy
73 	[FX_NOTESLIDEUP]        =  88, // IMF Gxy
74 	[FX_PANNING]            =  80,
75 	[FX_PANNINGSLIDE]       =  72,
76 	[FX_MIDI]               =  64,
77 	[FX_SPECIAL]            =  56,
78 	[FX_PANBRELLO]          =  48,
79 	[FX_VIBRATO]            =  40,
80 	[FX_FINEVIBRATO]        =  32,
81 	[FX_TREMOLO]            =  24,
82 	[FX_KEYOFF]             =  16,
83 	[FX_SETENVPOSITION]     =   8,
84 	[FX_NONE]               =   0,
85 };
86 
swap_effects(song_note_t * note)87 void swap_effects(song_note_t *note)
88 {
89 	song_note_t tmp = {
90 		.note = note->note,
91 		.instrument = note->instrument,
92 		.voleffect = note->effect,
93 		.volparam = note->param,
94 		.effect = note->voleffect,
95 		.param = note->volparam,
96 	};
97 	*note = tmp;
98 }
99 
convert_voleffect(uint8_t * e,uint8_t * p,int force)100 int convert_voleffect(uint8_t *e, uint8_t *p, int force)
101 {
102 	switch (*e) {
103 	case FX_NONE:
104 		return 1;
105 	case FX_VOLUME:
106 		*e = VOLFX_VOLUME;
107 		*p = MIN(*p, 64);
108 		break;
109 	case FX_PORTAMENTOUP:
110 		/* if not force, reject when dividing causes loss of data in LSB, or if the final value is too
111 		large to fit. (volume column Ex/Fx are four times stronger than effect column) */
112 		if (!force && ((*p & 3) || *p > 9 * 4 + 3))
113 			return 0;
114 		*p = MIN(*p / 4, 9);
115 		*e = VOLFX_PORTAUP;
116 		break;
117 	case FX_PORTAMENTODOWN:
118 		if (!force && ((*p & 3) || *p > 9 * 4 + 3))
119 			return 0;
120 		*p = MIN(*p / 4, 9);
121 		*e = VOLFX_PORTADOWN;
122 		break;
123 	case FX_TONEPORTAMENTO:
124 		if (*p >= 0xf0) {
125 			// hack for people who can't type F twice :)
126 			*e = VOLFX_TONEPORTAMENTO;
127 			*p = 0x9;
128 			return 1;
129 		}
130 		for (int n = 0; n < 10; n++) {
131 			if (force
132 			    ? (*p <= vc_portamento_table[n])
133 			    : (*p == vc_portamento_table[n])) {
134 				*e = VOLFX_TONEPORTAMENTO;
135 				*p = n;
136 				return 1;
137 			}
138 		}
139 		return 0;
140 	case FX_VIBRATO:
141 		if (force)
142 			*p = MIN(*p, 9);
143 		else if (*p > 9)
144 			return 0;
145 		*e = VOLFX_VIBRATODEPTH;
146 		break;
147 	case FX_FINEVIBRATO:
148 		if (force)
149 			*p = 0;
150 		else if (*p)
151 			return 0;
152 		*e = VOLFX_VIBRATODEPTH;
153 		break;
154 	case FX_PANNING:
155 		*p = MIN(64, *p * 64 / 255);
156 		*e = VOLFX_PANNING;
157 		break;
158 	case FX_VOLUMESLIDE:
159 		// ugh
160 		// (IT doesn't even attempt to do this, presumably since it'd screw up the effect memory)
161 		if (*p == 0)
162 			return 0;
163 		if ((*p & 0xf) == 0) { // Dx0 / Cx
164 			if (force)
165 				*p = MIN(*p >> 4, 9);
166 			else if ((*p >> 4) > 9)
167 				return 0;
168 			else
169 				*p >>= 4;
170 			*e = VOLFX_VOLSLIDEUP;
171 		} else if ((*p & 0xf0) == 0) { // D0x / Dx
172 			if (force)
173 				*p = MIN(*p, 9);
174 			else if (*p > 9)
175 				return 0;
176 			*e = VOLFX_VOLSLIDEDOWN;
177 		} else if ((*p & 0xf) == 0xf) { // DxF / Ax
178 			if (force)
179 				*p = MIN(*p >> 4, 9);
180 			else if ((*p >> 4) > 9)
181 				return 0;
182 			else
183 				*p >>= 4;
184 			*e = VOLFX_FINEVOLUP;
185 		} else if ((*p & 0xf0) == 0xf0) { // DFx / Bx
186 			if (force)
187 				*p = MIN(*p, 9);
188 			else if ((*p & 0xf) > 9)
189 				return 0;
190 			else
191 				*p &= 0xf;
192 			*e = VOLFX_FINEVOLDOWN;
193 		} else { // ???
194 			return 0;
195 		}
196 		break;
197 	case FX_SPECIAL:
198 		switch (*p >> 4) {
199 		case 8:
200 			/* Impulse Tracker imports XM volume-column panning very weirdly:
201 				XM = P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 PA PB PC PD PE PF
202 				IT = 00 05 10 15 20 21 30 31 40 45 42 47 60 61 62 63
203 			I'll be um, not duplicating that behavior. :) */
204 			*e = VOLFX_PANNING;
205 			*p = SHORT_PANNING(*p & 0xf);
206 			return 1;
207 		case 0: case 1: case 2: case 0xf:
208 			if (force) {
209 				*e = *p = 0;
210 				return 1;
211 			}
212 			break;
213 		default:
214 			break;
215 		}
216 		return 0;
217 	default:
218 		return 0;
219 	}
220 	return 1;
221 }
222 
223 
read_lined_message(char * msg,slurp_t * fp,int len,int linelen)224 void read_lined_message(char *msg, slurp_t *fp, int len, int linelen)
225 {
226 	int msgsize = 0, linesize;
227 
228 	while (len) {
229 		linesize = MIN(len, linelen);
230 		if (msgsize + linesize + 1 >= MAX_MESSAGE) {
231 			/* Skip the rest */
232 			slurp_seek(fp, len, SEEK_CUR);
233 			break;
234 		}
235 
236 		slurp_read(fp, msg, linesize);
237 		len -= linesize;
238 
239 		msg[linesize] = '\0';
240 		linesize = rtrim_string(msg);
241 		msgsize += linesize + 1;
242 		msg += linesize;
243 		*msg++ = '\n';
244 	}
245 	*msg = '\0';
246 }
247 
248