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