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 #include "headers.h"
24 #include "it.h"
25 #include "page.h"
26 #include "song.h"
27 
28 #include <math.h>
29 
30 #define NATIVE_SCREEN_WIDTH     640
31 #define NATIVE_SCREEN_HEIGHT    400
32 #define FUDGE_256_TO_WIDTH      4
33 #define SCOPE_ROWS      32
34 
35 
36 /* consts */
37 #define FFT_BUFFER_SIZE_LOG     11
38 #define FFT_BUFFER_SIZE         2048 /*(1 << FFT_BUFFER_SIZE_LOG)*/
39 #define FFT_OUTPUT_SIZE         1024 /* FFT_BUFFER_SIZE/2 */  /*WARNING: Hardcoded in page.c when declaring current_fft_data*/
40 #define FFT_BANDS_SIZE          256    /*WARNING: Hardcoded in page.c when declaring fftlog and when using it in vis_fft*/
41 #define PI      ((double)3.14159265358979323846)
42 /*This value is used internally to scale the power output of the FFT to decibells.*/
43 static const float fft_inv_bufsize = 1.0f/(FFT_BUFFER_SIZE>>2);
44 /*Scaling for FFT. Input is expected to be signed short int.*/
45 static const float inv_s_range = 1.f/32768.f;
46 
47 short current_fft_data[2][FFT_OUTPUT_SIZE];
48 /*Table to change the scale from linear to log.*/
49 short fftlog[FFT_BANDS_SIZE];
50 
51 void vis_init(void);
52 void vis_work_16s(short *in, int inlen);
53 void vis_work_16m(short *in, int inlen);
54 void vis_work_8s(char *in, int inlen);
55 void vis_work_8m(char *in, int inlen);
56 
57 /* variables :) */
58 static int mono = 0;
59 //gain, in dBs.
60 //static int gain = 0;
61 static int noisefloor=72;
62 
63 /* get the _whole_ display */
64 static struct vgamem_overlay ovl = { 0, 0, 79, 49, NULL, 0, 0, 0 };
65 
66 /* tables */
67 static unsigned int bit_reverse[FFT_BUFFER_SIZE];
68 static float window[FFT_BUFFER_SIZE];
69 static float precos[FFT_OUTPUT_SIZE];
70 static float presin[FFT_OUTPUT_SIZE];
setup_channel_filter(song_voice_t * chan,int reset,int flt_modifier,int freq)71 
72 /* fft state */
73 static float state_real[FFT_BUFFER_SIZE];
74 static float state_imag[FFT_BUFFER_SIZE];
75 
76 
77 static int _reverse_bits(unsigned int in) {
78 	unsigned int r = 0, n;
79 	for (n = 0; n < FFT_BUFFER_SIZE_LOG; n++) {
80 		r <<= 1;
81 		r += (in & 1);
82 		in >>= 1;
83 	}
84 	return r;
85 }
86 void vis_init(void)
87 {
88 	unsigned n;
89 
90 	for (n = 0; n < FFT_BUFFER_SIZE; n++) {
91 		bit_reverse[n] = _reverse_bits(n);
92 #if 0
93 		/*Rectangular/none*/
94 		window[n] = 1;
95 		/*Cosine/sine window*/
96 		window[n] = sin(PI * n/ FFT_BUFFER_SIZE -1);
97 		/*Hann Window*/
98 		window[n] = 0.50f - 0.50f * cos(2.0*PI * n / (FFT_BUFFER_SIZE - 1));
99 		/*Hamming Window*/
100 		window[n] = 0.54f - 0.46f * cos(2.0*PI * n / (FFT_BUFFER_SIZE - 1));
101 		/*Gaussian*/
102 		window[n] = powf(M_E,-0.5f *pow((n-(FFT_BUFFER_SIZE-1)/2.f)/(0.4*(FFT_BUFFER_SIZE-1)/2.f),2.f));
103 		/*Blackmann*/
104 		window[n] = 0.42659 - 0.49656 * cos(2.0*PI * n/ (FFT_BUFFER_SIZE-1)) + 0.076849 * cos(4.0*PI * n /(FFT_BUFFER_SIZE-1));
105 		/*Blackman-Harris*/
106 		window[n] = 0.35875 - 0.48829 * cos(2.0*PI * n/ (FFT_BUFFER_SIZE-1)) + 0.14128 * cos(4.0*PI * n /(FFT_BUFFER_SIZE-1)) - 0.01168 * cos(6.0*PI * n /(FFT_BUFFER_SIZE-1));
107 #endif
108 		/*Hann Window*/
109 		window[n] = 0.50f - 0.50f * cos(2.0*PI * n / (FFT_BUFFER_SIZE - 1));
110 	}
111 	for (n = 0; n < FFT_OUTPUT_SIZE; n++) {
112 		float j = (2.0*PI) * n / FFT_BUFFER_SIZE;
113 		precos[n] = cos(j);
114 		presin[n] = sin(j);
115 	}
116 #if 0
117 	/*linear*/
118 	fftlog[n]=n;
119 #elif 1
120 	/*exponential.*/
121 	float factor = (float)FFT_OUTPUT_SIZE/(FFT_BANDS_SIZE*FFT_BANDS_SIZE);
122 	for (n = 0; n < FFT_BANDS_SIZE; n++ ) {
123 		fftlog[n]=n*n*factor;
124 	}
125 #else
126 	/*constant note scale.*/
127 	float factor = 8.f/(float)FFT_BANDS_SIZE;
128 	float factor2 = (float)FFT_OUTPUT_SIZE/256.f;
129 	for (n = 0; n < FFT_BANDS_SIZE; n++ ) {
130 		fftlog[n]=(powf(2.0f,n*factor)-1.f)*factor2;
131 	}
132 #endif
133 }
134 
135 /*
136 * Understanding In and Out:
137 * input is the samples (so, it is amplitude). The scale is expected to be signed 16bits.
138 *    The window function calculated in "window" will automatically be applied.
139 * output is a value between 0 and 128 representing 0 = noisefloor variable
140 *    and 128 = 0dBFS (deciBell, FullScale) for each band.
141 */
142 static inline void _vis_data_work(short output[FFT_OUTPUT_SIZE],
143 			short input[FFT_BUFFER_SIZE])
144 {
145 	unsigned int n, k, y;
146 	unsigned int ex, ff;
147 	float fr, fi;
148 	float tr, ti;
149 	float out;
150 	int yp;
151 
152 	/* fft */
153 	float *rp = state_real;
154 	float *ip = state_imag;
155 	for (n = 0; n < FFT_BUFFER_SIZE; n++) {
156 		int nr = bit_reverse[n];
157 		*rp++ = (float)input[ nr ] * inv_s_range * window[nr];
158 		*ip++ = 0;
159 	}
160 	ex = 1;
161 	ff = FFT_OUTPUT_SIZE;
162 	for (n = FFT_BUFFER_SIZE_LOG; n != 0; n--) {
163 		for (k = 0; k != ex; k++) {
164 			fr = precos[k * ff];
165 			fi = presin[k * ff];
166 			for (y = k; y < FFT_BUFFER_SIZE; y += ex << 1) {
167 				yp = y + ex;
168 				tr = fr * state_real[yp] - fi * state_imag[yp];
169 				ti = fr * state_imag[yp] + fi * state_real[yp];
170 				state_real[yp] = state_real[y] - tr;
171 				state_imag[yp] = state_imag[y] - ti;
172 				state_real[y] += tr;
173 				state_imag[y] += ti;
174 			}
175 		}
176 		ex <<= 1;
177 		ff >>= 1;
178 	}
179 
180 	/* collect fft */
181 	rp = state_real; rp++;
182 	ip = state_imag; ip++;
183 	const float fft_dbinv_bufsize = dB(fft_inv_bufsize);
184 	for (n = 0; n < FFT_OUTPUT_SIZE; n++) {
185 		/* "out" is the total power for each band.
186 		* To get amplitude from "output", use sqrt(out[N])/(sizeBuf>>2)
187 		* To get dB from "output", use powerdB(out[N])+db(1/(sizeBuf>>2)).
188 		* powerdB is = 10 * log10(in)
189 		* dB is = 20 * log10(in)
190 		*/
191 		out = ((*rp) * (*rp)) + ((*ip) * (*ip));
192 		/* +0.0000000001f is -100dB of power. Used to prevent evaluating powerdB(0.0) */
193 		output[n] = pdB_s(noisefloor, out+0.0000000001f,fft_dbinv_bufsize);
194 		rp++;ip++;
195 	}
196 }
197 /* convert the fft bands to columns of screen
198 out and d have a range of 0 to 128 */
199 static inline void _get_columns_from_fft(unsigned char *out,
200 				short d[FFT_OUTPUT_SIZE], int m)
201 {
202 	int i, j, a;
203 	for (i = 0, a=0; i < FFT_BANDS_SIZE; i++)  {
204 		float afloat = fftlog[i];
205 		float floora = floor(afloat);
206 		if ((i == FFT_BANDS_SIZE -1) || (afloat + 1.0f > fftlog[i+1])) {
207 			a = (int)floora;
208 			j = d[a] + (d[a+1]-d[a])*(afloat-floora);
209 			a = floor(afloat+0.5f);
210 		}
211 		else {
212 			j=d[a];
213 			while(a<=afloat){
214 				j = MAX(j,d[a]);
215 				a++;
216 			}
217 		}
218 		*out = j; out++;
219 		/*If mono, repeat the value.*/
220 		if (m) { *out = j; out++; }
221 		if ((i % FUDGE_256_TO_WIDTH) == 0) {
222 			/* each band is 2.50 px wide;
223 			 * output display is 640 px
224 			 */
225 			*out = j; out++;
226 			/*If mono, repeat the value.*/
227 			if (m) { *out = j; out++; }
228 		}
229 	}
230 }
231 
232 /* Convert the output of */
233 static inline unsigned char *_dobits(unsigned char *q,
234 			unsigned char *in, int length, int y)
235 {
236 	int i, c;
237 	for (i = 0; i < length; i++)  {
238 		/* j is has range 0 to 128. Now use the upper side for drawing.*/
239 		c = 128 + in[i];
240 		if (c > 255) c = 255;
241 		*q = c; q += y;
242 	}
243 	return q;
244 }
245 /*x = screen.x, h = 0..128, c = colour */
246 static inline void _drawslice(int x, int h, int c)
247 {
248 	int y;
249 
250 	y = ((h>>2) & (SCOPE_ROWS-1))+1;
251 	vgamem_ovl_drawline(&ovl,
252 		x, (NATIVE_SCREEN_HEIGHT-y),
253 		x, (NATIVE_SCREEN_HEIGHT-1), c);
254 }
255 static void _vis_process(void)
256 {
257 	unsigned char *q;
258 	int i, k;
259 	k = NATIVE_SCREEN_WIDTH/2;
260 	unsigned char outfft[NATIVE_SCREEN_WIDTH];
261 
262 	vgamem_lock();
263 
264 	/* move up by one pixel */
265 	memmove(ovl.q, ovl.q+NATIVE_SCREEN_WIDTH,
266 			(NATIVE_SCREEN_WIDTH*
267 				((NATIVE_SCREEN_HEIGHT-1)-SCOPE_ROWS)));
268 	q = ovl.q + (NATIVE_SCREEN_WIDTH*
269 			((NATIVE_SCREEN_HEIGHT-1)-SCOPE_ROWS));
270 
271 	if (mono) {
272 		for (i = 0; i < FFT_OUTPUT_SIZE; i++)
273 			current_fft_data[0][i] = (current_fft_data[0][i]
274 					+ current_fft_data[1][i]) / 2;
275 		_get_columns_from_fft(outfft, current_fft_data[0], 1);
276 		_dobits(q, outfft, NATIVE_SCREEN_WIDTH, 1);
277 	} else {
278 		_get_columns_from_fft(outfft, current_fft_data[0], 0);
279 		_dobits(q+k, outfft, k, -1);
280 		_get_columns_from_fft(outfft+k, current_fft_data[1], 0);
281 		_dobits(q+k, outfft+k, k, 1);
282 	}
283 
284 	/* draw the scope at the bottom */
285 	q = ovl.q + (NATIVE_SCREEN_WIDTH*(NATIVE_SCREEN_HEIGHT-SCOPE_ROWS));
286 	i = SCOPE_ROWS*NATIVE_SCREEN_WIDTH;
287 	memset(q,0,i);
288 	if (mono) {
289 		for (i = 0; i < NATIVE_SCREEN_WIDTH; i++) {
290 			_drawslice(i, outfft[i],5);
291 		}
292 	} else {
293 		for (i = 0; i < k; i++) {
294 			_drawslice(k-i-1, outfft[i],5);
295 		}
296 		for (i = 0; i < k; i++) {
297 			_drawslice(k+i, outfft[k+i],5);
298 		}
299 	}
300 
301 	vgamem_unlock();
302 	status.flags |= NEED_UPDATE;
303 }
304 
305 void vis_work_16s(short *in, int inlen)
306 {
307 	short dl[FFT_BUFFER_SIZE];
308 	short dr[FFT_BUFFER_SIZE];
309 	int i, j, k;
310 
311 	if (!inlen) {
312 		memset(current_fft_data[0], 0, FFT_OUTPUT_SIZE*2);
313 		memset(current_fft_data[1], 0, FFT_OUTPUT_SIZE*2);
314 	} else {
315 		for (i = 0; i < FFT_BUFFER_SIZE;) {
316 			for (k = j = 0; k < inlen && i < FFT_BUFFER_SIZE; k++, i++) {
317 				dl[i] = in[j]; j++;
318 				dr[i] = in[j]; j++;
319 			}
320 		}
321 		_vis_data_work(current_fft_data[0], dl);
322 		_vis_data_work(current_fft_data[1], dr);
323 	}
324 	if (status.current_page == PAGE_WATERFALL) _vis_process();
325 }
326 void vis_work_16m(short *in, int inlen)
327 {
328 	short d[FFT_BUFFER_SIZE];
329 	int i, k;
330 
331 	if (!inlen) {
332 		memset(current_fft_data[0], 0, FFT_OUTPUT_SIZE*2);
333 		memset(current_fft_data[1], 0, FFT_OUTPUT_SIZE*2);
334 	} else {
335 		for (i = 0; i < FFT_BUFFER_SIZE;) {
336 			for (k = 0; k < inlen && i < FFT_BUFFER_SIZE; k++, i++) {
337 				d[i] = in[k];
338 			}
339 		}
340 		_vis_data_work(current_fft_data[0], d);
341 		memcpy(current_fft_data[1], current_fft_data[0], FFT_OUTPUT_SIZE * 2);
342 	}
343 	if (status.current_page == PAGE_WATERFALL) _vis_process();
344 }
345 
346 void vis_work_8s(char *in, int inlen)
347 {
348 	short dl[FFT_BUFFER_SIZE];
349 	short dr[FFT_BUFFER_SIZE];
350 	int i, j, k;
351 
352 	if (!inlen) {
353 		memset(current_fft_data[0], 0, FFT_OUTPUT_SIZE*2);
354 		memset(current_fft_data[1], 0, FFT_OUTPUT_SIZE*2);
355 	} else {
356 		for (i = 0; i < FFT_BUFFER_SIZE;) {
357 			for (k = j = 0; k < inlen && i < FFT_BUFFER_SIZE; k++, i++) {
358 				dl[i] = ((short)in[j]) * 256; j++;
359 				dr[i] = ((short)in[j]) * 256; j++;
360 			}
361 		}
362 		_vis_data_work(current_fft_data[0], dl);
363 		_vis_data_work(current_fft_data[1], dr);
364 	}
365 	if (status.current_page == PAGE_WATERFALL) _vis_process();
366 }
367 void vis_work_8m(char *in, int inlen)
368 {
369 	short d[FFT_BUFFER_SIZE];
370 	int i, k;
371 
372 	if (!inlen) {
373 		memset(current_fft_data[0], 0, FFT_OUTPUT_SIZE*2);
374 		memset(current_fft_data[1], 0, FFT_OUTPUT_SIZE*2);
375 	} else {
376 		for (i = 0; i < FFT_BUFFER_SIZE;) {
377 			for (k = 0; k < inlen && i < FFT_BUFFER_SIZE; k++, i++) {
378 				d[i] = ((short)in[k]) * 256;
379 			}
380 		}
381 		_vis_data_work(current_fft_data[0], d);
382 		memcpy(current_fft_data[1],
383 				 current_fft_data[0], FFT_OUTPUT_SIZE * 2);
384 	}
385 	if (status.current_page == PAGE_WATERFALL) _vis_process();
386 }
387 
388 static void draw_screen(void)
389 {
390 	/* waterfall uses a single overlay */
391 	vgamem_ovl_apply(&ovl);
392 }
393 
394 static int waterfall_handle_key(struct key_event *k)
395 {
396 	int n, v, order, ii;
397 
398 	if (NO_MODIFIER(k->mod)) {
399 		if (k->midi_note > -1) {
400 			n = k->midi_note;
401 			if (k->midi_volume > -1) {
402 				v = k->midi_volume / 2;
403 			} else {
404 				v = 64;
405 			}
406 		} else {
407 			v = 64;
408 			n = kbd_get_note(k);
409 		}
410 		if (n > -1) {
411 			if (song_is_instrument_mode()) {
412 				ii = instrument_get_current();
413 			} else {
414 				ii = sample_get_current();
415 			}
416 			if (k->state == KEY_RELEASE) {
417 				song_keyup(KEYJAZZ_NOINST, ii, n);
418 				status.last_keysym = 0;
419 			} else if (!k->is_repeat) {
420 				song_keydown(KEYJAZZ_NOINST, ii, n, v, KEYJAZZ_CHAN_CURRENT);
421 			}
422 			return 1;
423 		}
424 	}
425 
426 	switch (k->sym) {
427 	case SDLK_s:
428 		if (k->mod & KMOD_ALT) {
429 			if (k->state == KEY_RELEASE)
430 				return 1;
431 
432 			song_toggle_stereo();
433 			status.flags |= NEED_UPDATE;
434 			return 1;
435 		}
436 		return 0;
437 	case SDLK_m:
438 		if (k->mod & KMOD_ALT) {
439 			if (k->state == KEY_RELEASE)
440 				return 1;
441 			mono = !mono;
442 			return 1;
443 		}
444 		return 0;
445 	case SDLK_LEFT:
446 		if (!NO_MODIFIER(k->mod))
447 			return 0;
448 		if (k->state == KEY_RELEASE)
449 			return 1;
450 		noisefloor-=4;
451 		break;
452 	case SDLK_RIGHT:
453 		if (!NO_MODIFIER(k->mod))
454 			return 0;
455 		if (k->state == KEY_RELEASE)
456 			return 1;
457 		noisefloor+=4;
458 		break;
459 	case SDLK_g:
460 		if (k->mod & KMOD_ALT) {
461 			if (k->state == KEY_PRESS)
462 				return 1;
463 
464 			order = song_get_current_order();
465 			if (song_get_mode() == MODE_PLAYING) {
466 				n = current_song->orderlist[order];
467 			} else {
468 				n = song_get_playing_pattern();
469 			}
470 			if (n < 200) {
471 				set_current_order(order);
472 				set_current_pattern(n);
473 				set_current_row(song_get_current_row());
474 				set_page(PAGE_PATTERN_EDITOR);
475 			}
476 			return 1;
477 		}
478 		return 0;
479 	case SDLK_r:
480 		if (k->mod & KMOD_ALT) {
481 			if (k->state == KEY_RELEASE)
482 				return 1;
483 
484 			song_flip_stereo();
485 			return 1;
486 		}
487 		return 0;
488 	case SDLK_PLUS:
489 		if (!NO_MODIFIER(k->mod))
490 			return 0;
491 		if (k->state == KEY_RELEASE)
492 			return 1;
493 		if (song_get_mode() == MODE_PLAYING) {
494 			song_set_current_order(song_get_current_order() + 1);
495 		}
496 		return 1;
497 	case SDLK_MINUS:
498 		if (!NO_MODIFIER(k->mod))
499 			return 0;
500 		if (k->state == KEY_RELEASE)
501 			return 1;
502 		if (song_get_mode() == MODE_PLAYING) {
503 			song_set_current_order(song_get_current_order() - 1);
504 		}
505 		return 1;
506 	case SDLK_SEMICOLON:
507 	case SDLK_COLON:
508 		if (k->state == KEY_RELEASE)
509 			return 1;
510 		if (song_is_instrument_mode()) {
511 			instrument_set(instrument_get_current() - 1);
512 		} else {
513 			sample_set(sample_get_current() - 1);
514 		}
515 		return 1;
516 	case SDLK_QUOTE:
517 	case SDLK_QUOTEDBL:
518 		if (k->state == KEY_RELEASE)
519 			return 1;
520 		if (song_is_instrument_mode()) {
521 			instrument_set(instrument_get_current() + 1);
522 		} else {
523 			sample_set(sample_get_current() + 1);
524 		}
525 		return 1;
526 	case SDLK_COMMA:
527 	case SDLK_LESS:
528 		if (k->state == KEY_RELEASE)
529 			return 1;
530 		song_change_current_play_channel(-1, 0);
531 		return 1;
532 	case SDLK_PERIOD:
533 	case SDLK_GREATER:
534 		if (k->state == KEY_RELEASE)
535 			return 1;
536 		song_change_current_play_channel(1, 0);
537 		return 1;
538 	default:
539 		return 0;
540 	};
541 
542 	noisefloor = CLAMP(noisefloor, 36, 96);
543 	return 1;
544 }
545 
546 
547 static struct widget waterfall_widget_hack[1];
548 static void do_nil(void) {}
549 
550 static void waterfall_set_page(void)
551 {
552 	vgamem_ovl_clear(&ovl, 0);
553 }
554 void waterfall_load_page(struct page *page)
555 {
556 	vgamem_ovl_alloc(&ovl);
557 	page->title = "";
558 	page->draw_full = draw_screen;
559 	page->set_page = waterfall_set_page;
560 	page->total_widgets = 1;
561 	page->widgets = waterfall_widget_hack;
562 	create_other(waterfall_widget_hack, 0, waterfall_handle_key, do_nil);
563 }
564