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
26 #include "it.h"
27 #include "song.h"
28 #include "page.h"
29 #include "video.h"
30
31 #include "sdlmain.h"
32
33 #include <math.h>
34
35 #define SAMPLE_DATA_COLOR 13 /* Sample data */
36 #define SAMPLE_LOOP_COLOR 3 /* Sample loop marks */
37 #define SAMPLE_MARK_COLOR 6 /* Play mark color */
38 #define SAMPLE_BGMARK_COLOR 7 /* Play mark color after note fade / NNA */
39
40 /* --------------------------------------------------------------------- */
41 /* sample drawing
42 there are only two changes between 8- and 16-bit samples:
43 - the type of 'data'
44 - the amount to divide (note though, this number is used twice!)
45
46 output channels = number of oscis
47 input channels = number of channels in data
48 */
49
_draw_sample_data_8(struct vgamem_overlay * r,signed char * data,unsigned long length,unsigned int inputchans,unsigned int outputchans)50 static void _draw_sample_data_8(struct vgamem_overlay *r,
51 signed char *data, unsigned long length, unsigned int inputchans, unsigned int outputchans)
52 {
53 unsigned long pos;
54 unsigned int cc, co;
55 int level, xs, ys, xe, ye, step;
56 int nh, np;
57 int chip;
58
59 nh = (r->height / outputchans);
60 np = r->height - (nh / 2);
61
62 length /= inputchans;
63 chip = (length < (unsigned int) r->width * 2);
64
65 for (cc = 0; cc < outputchans; cc++) {
66 pos = 0;
67 co = 0;
68 step = MAX(1, (length / r->width) >> 8);
69 level=0;
70 do {
71 level+=ceil(data[(pos * inputchans) + cc+co] * nh / (float)(SCHAR_MAX - SCHAR_MIN + 1));
72 } while (co++ < inputchans-outputchans);
73 xs = 0;
74 ys = (np - 1) - level;
75 ys = CLAMP(ys, 0, r->height - 1);
76 do {
77 pos += step;
78 co = 0;
79 level=0;
80 do {
81 level+=ceil(data[(pos * inputchans) + cc+co] * nh / (SCHAR_MAX - SCHAR_MIN + 1));
82 } while (co++ < inputchans-outputchans);
83 xe = pos * r->width / length;
84 ye = (np - 1) - level;
85 xe = CLAMP(xe, 0, r->width - 1);
86 ye = CLAMP(ye, 0, r->height - 1);
87 // 'ye' is more or less useless for small samples, but this is much cleaner
88 // code than writing nearly the same loop four different times :P
89 vgamem_ovl_drawline(r, xs, ys, xe, chip ? ys : ye, SAMPLE_DATA_COLOR);
90 xs = xe;
91 ys = ye;
92 } while (pos < length);
93 np -= nh;
94 }
95 }
96
_draw_sample_data_16(struct vgamem_overlay * r,signed short * data,unsigned long length,unsigned int inputchans,unsigned int outputchans)97 static void _draw_sample_data_16(struct vgamem_overlay *r,
98 signed short *data, unsigned long length, unsigned int inputchans, unsigned int outputchans)
99 {
100 unsigned long pos;
101 unsigned int cc, co;
102 int level, xs, ys, xe, ye, step;
103 int nh, np;
104 int chip;
105
106 nh = (r->height / outputchans);
107 np = r->height - (nh / 2);
108
109 length /= inputchans;
110 chip = (length < (unsigned int) r->width * 2);
111
112 for (cc = 0; cc < outputchans; cc++) {
113 pos = 0;
114 co = 0;
115 step = MAX(1, (length / r->width) >> 8);
116 level=0;
117 do {
118 level += ceil(data[(pos * inputchans) + cc+co] * nh / (float)(SHRT_MAX - SHRT_MIN + 1));
119 } while(co++ < inputchans-outputchans);
120 xs = 0;
121 ys = (np - 1) - level;
122 ys = CLAMP(ys, 0, r->height - 1);
123 do {
124 pos += step;
125 co = 0;
126 level = 0;
127 do {
128 level = ceil(data[(pos * inputchans) + cc+co] * nh / (float)(SHRT_MAX - SHRT_MIN + 1));
129 } while (co++ < inputchans-outputchans);
130 xe = pos * r->width / length;
131 ye = (np - 1) - level;
132 xe = CLAMP(xe, 0, r->width - 1);
133 ye = CLAMP(ye, 0, r->height - 1);
134 vgamem_ovl_drawline(r, xs, ys, xe, chip ? ys : ye, SAMPLE_DATA_COLOR);
135 xs = xe;
136 ys = ye;
137 } while (pos < length);
138 np -= nh;
139 }
140 }
141
142 /* --------------------------------------------------------------------- */
143 /* these functions assume the screen is locked! */
144
145 /* loop drawing */
_draw_sample_loop(struct vgamem_overlay * r,song_sample_t * sample)146 static void _draw_sample_loop(struct vgamem_overlay *r, song_sample_t * sample)
147 {
148 int loopstart, loopend, y;
149 int c = ((status.flags & CLASSIC_MODE) ? SAMPLE_DATA_COLOR : SAMPLE_LOOP_COLOR);
150
151 if (!(sample->flags & CHN_LOOP))
152 return;
153
154 loopstart = sample->loop_start * (r->width - 1) / sample->length;
155 loopend = sample->loop_end * (r->width - 1) / sample->length;
156
157 y = 0;
158 do {
159 vgamem_ovl_drawpixel(r, loopstart, y, 0); vgamem_ovl_drawpixel(r, loopend, y, 0); y++;
160 vgamem_ovl_drawpixel(r, loopstart, y, c); vgamem_ovl_drawpixel(r, loopend, y, c); y++;
161 vgamem_ovl_drawpixel(r, loopstart, y, c); vgamem_ovl_drawpixel(r, loopend, y, c); y++;
162 vgamem_ovl_drawpixel(r, loopstart, y, 0); vgamem_ovl_drawpixel(r, loopend, y, 0); y++;
163 } while (y < r->height);
164 }
165
_draw_sample_susloop(struct vgamem_overlay * r,song_sample_t * sample)166 static void _draw_sample_susloop(struct vgamem_overlay *r, song_sample_t * sample)
167 {
168 int loopstart, loopend, y;
169 int c = ((status.flags & CLASSIC_MODE) ? SAMPLE_DATA_COLOR : SAMPLE_LOOP_COLOR);
170
171 if (!(sample->flags & CHN_SUSTAINLOOP))
172 return;
173
174 loopstart = sample->sustain_start * (r->width - 1) / sample->length;
175 loopend = sample->sustain_end * (r->width - 1) / sample->length;
176
177 y = 0;
178 do {
179 vgamem_ovl_drawpixel(r, loopstart, y, c); vgamem_ovl_drawpixel(r, loopend, y, c); y++;
180 vgamem_ovl_drawpixel(r, loopstart, y, 0); vgamem_ovl_drawpixel(r, loopend, y, 0); y++;
181 vgamem_ovl_drawpixel(r, loopstart, y, c); vgamem_ovl_drawpixel(r, loopend, y, c); y++;
182 vgamem_ovl_drawpixel(r, loopstart, y, 0); vgamem_ovl_drawpixel(r, loopend, y, 0); y++;
183 } while (y < r->height);
184 }
185
186 /* this does the lines for playing samples */
_draw_sample_play_marks(struct vgamem_overlay * r,song_sample_t * sample)187 static void _draw_sample_play_marks(struct vgamem_overlay *r, song_sample_t * sample)
188 {
189 int n, x, y;
190 int c;
191 song_voice_t *channel;
192 unsigned int *channel_list;
193
194 if (song_get_mode() == MODE_STOPPED)
195 return;
196
197 song_lock_audio();
198
199 n = song_get_mix_state(&channel_list);
200 while (n--) {
201 channel = song_get_mix_channel(channel_list[n]);
202 if (channel->current_sample_data != sample->data)
203 continue;
204 if (!channel->final_volume) continue;
205 c = (channel->flags & (CHN_KEYOFF | CHN_NOTEFADE)) ? SAMPLE_BGMARK_COLOR : SAMPLE_MARK_COLOR;
206 x = channel->position * (r->width - 1) / sample->length;
207 if (x >= r->width) {
208 /* this does, in fact, happen :( */
209 continue;
210 }
211 y = 0;
212 do {
213 /* unrolled 8 times */
214 vgamem_ovl_drawpixel(r, x, y++, c);
215 vgamem_ovl_drawpixel(r, x, y++, c);
216 vgamem_ovl_drawpixel(r, x, y++, c);
217 vgamem_ovl_drawpixel(r, x, y++, c);
218 vgamem_ovl_drawpixel(r, x, y++, c);
219 vgamem_ovl_drawpixel(r, x, y++, c);
220 vgamem_ovl_drawpixel(r, x, y++, c);
221 vgamem_ovl_drawpixel(r, x, y++, c);
222 } while (y < r->height);
223 }
224
225 song_unlock_audio();
226 }
227
228 /* --------------------------------------------------------------------- */
229 /* meat! */
230
draw_sample_data(struct vgamem_overlay * r,song_sample_t * sample)231 void draw_sample_data(struct vgamem_overlay *r, song_sample_t *sample)
232 {
233 vgamem_ovl_clear(r, 0);
234
235 if (sample->flags & CHN_ADLIB) {
236 vgamem_ovl_clear(r, 2);
237 vgamem_ovl_apply(r);
238 char buf1[32], buf2[32];
239
240 int y1 = r->y1, y2 = y1+3;
241
242 draw_box(59,y1, 77,y2, BOX_THICK | BOX_INNER | BOX_INSET); // data
243 draw_box(54,y1, 58,y2, BOX_THIN | BOX_INNER | BOX_OUTSET); // button
244 draw_text_len("Mod", 3, 55,y1+1, 0,2);
245 draw_text_len("Car", 3, 55,y1+2, 0,2);
246
247 sprintf(buf1, "%02X %02X %02X %02X %02X %02X", // length:6*3-1=17
248 sample->adlib_bytes[0],
249 sample->adlib_bytes[2],
250 sample->adlib_bytes[4],
251 sample->adlib_bytes[6],
252 sample->adlib_bytes[8],
253 sample->adlib_bytes[10]);
254 sprintf(buf2, "%02X %02X %02X %02X %02X", // length: 5*3-1=14
255 sample->adlib_bytes[1],
256 sample->adlib_bytes[3],
257 sample->adlib_bytes[5],
258 sample->adlib_bytes[7],
259 sample->adlib_bytes[9]);
260 draw_text_len(buf1, 17, 60,y1+1, 2,0);
261 draw_text_len(buf2, 17, 60,y1+2, 2,0);
262 return;
263 }
264
265 if (!sample->length || !sample->data) {
266 vgamem_ovl_apply(r);
267 return;
268 }
269
270 /* do the actual drawing */
271 int chans = sample->flags & CHN_STEREO ? 2 : 1;
272 if (sample->flags & CHN_16BIT)
273 _draw_sample_data_16(r, (signed short *) sample->data,
274 sample->length * chans,
275 chans, chans);
276 else
277 _draw_sample_data_8(r, sample->data,
278 sample->length * chans,
279 chans, chans);
280
281 if ((status.flags & CLASSIC_MODE) == 0)
282 _draw_sample_play_marks(r, sample);
283 _draw_sample_loop(r, sample);
284 _draw_sample_susloop(r, sample);
285 vgamem_ovl_apply(r);
286 }
287
draw_sample_data_rect_16(struct vgamem_overlay * r,signed short * data,int length,unsigned int inputchans,unsigned int outputchans)288 void draw_sample_data_rect_16(struct vgamem_overlay *r, signed short *data,
289 int length, unsigned int inputchans, unsigned int outputchans)
290 {
291 vgamem_ovl_clear(r, 0);
292 _draw_sample_data_16(r, data, length, inputchans, outputchans);
293 vgamem_ovl_apply(r);
294 }
295
draw_sample_data_rect_8(struct vgamem_overlay * r,signed char * data,int length,unsigned int inputchans,unsigned int outputchans)296 void draw_sample_data_rect_8(struct vgamem_overlay *r, signed char *data,
297 int length, unsigned int inputchans, unsigned int outputchans)
298 {
299 vgamem_ovl_clear(r, 0);
300 _draw_sample_data_8(r, data, length, inputchans, outputchans);
301 vgamem_ovl_apply(r);
302 }
303
304