|  | @@ -73,12 +73,15 @@ struct visu_packet {
 | 
	
		
			
				|  |  |  	u8_t which;
 | 
	
		
			
				|  |  |  	u8_t count;
 | 
	
		
			
				|  |  |  	union {
 | 
	
		
			
				|  |  | -		union {
 | 
	
		
			
				|  |  | -			struct {
 | 
	
		
			
				|  |  | +		struct {
 | 
	
		
			
				|  |  | +			u32_t width;
 | 
	
		
			
				|  |  | +			union {
 | 
	
		
			
				|  |  | +				struct {
 | 
	
		
			
				|  |  |  				u32_t bars;
 | 
	
		
			
				|  |  |  				u32_t spectrum_scale;
 | 
	
		
			
				|  |  | -			};
 | 
	
		
			
				|  |  | -			u32_t style;	
 | 
	
		
			
				|  |  | +				};
 | 
	
		
			
				|  |  | +				u32_t style;	
 | 
	
		
			
				|  |  | +			};	
 | 
	
		
			
				|  |  |  		} full;	
 | 
	
		
			
				|  |  |  		struct {	
 | 
	
		
			
				|  |  |  			u32_t width;
 | 
	
	
		
			
				|  | @@ -180,6 +183,7 @@ static struct {
 | 
	
		
			
				|  |  |  #define VISU_ESP32	0x10
 | 
	
		
			
				|  |  |  static EXT_RAM_ATTR struct {
 | 
	
		
			
				|  |  |  	int bar_gap, bar_width, bar_border;
 | 
	
		
			
				|  |  | +	bool rotate;
 | 
	
		
			
				|  |  |  	struct {
 | 
	
		
			
				|  |  |  		int current, max;
 | 
	
		
			
				|  |  |  		int limit;
 | 
	
	
		
			
				|  | @@ -577,7 +581,7 @@ static void vfdc_handler( u8_t *_data, int bytes_read) {
 | 
	
		
			
				|  |  |  /****************************************************************************************
 | 
	
		
			
				|  |  |   * Display VU-Meter (lots of hard-coding)
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -void draw_VU(struct GDS_Device * display, const uint8_t *data, int level, int x, int y, int width) {
 | 
	
		
			
				|  |  | +void draw_VU(struct GDS_Device * display, const uint8_t *data, int level, int x, int y, int width, bool rotate) {
 | 
	
		
			
				|  |  |  	// VU data is by columns and vertical flip to allow block offset 
 | 
	
		
			
				|  |  |  	data += level * VU_WIDTH * VU_HEIGHT;
 | 
	
		
			
				|  |  |  	
 | 
	
	
		
			
				|  | @@ -593,10 +597,18 @@ void draw_VU(struct GDS_Device * display, const uint8_t *data, int level, int x,
 | 
	
		
			
				|  |  |  	int scale = 8 - GDS_GetDepth(display);
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  |  	// use "fast" version as we are not beyond screen boundaries
 | 
	
		
			
				|  |  | -	for (int r = 0; r < width; r++) {
 | 
	
		
			
				|  |  | -		for (int c = 0; c < VU_HEIGHT; c++) {
 | 
	
		
			
				|  |  | -			GDS_DrawPixelFastExt(display, r + x, c + y, *data++ >> scale);
 | 
	
		
			
				|  |  | +	if (visu.rotate) {
 | 
	
		
			
				|  |  | +		for (int r = 0; r < width; r++) {
 | 
	
		
			
				|  |  | +			for (int c = VU_HEIGHT; --c >= 0;) {
 | 
	
		
			
				|  |  | +				GDS_DrawPixelFastExt(display, c + x, r + y, *data++ >> scale);
 | 
	
		
			
				|  |  | +			}	
 | 
	
		
			
				|  |  |  		}	
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		for (int r = 0; r < width; r++) {
 | 
	
		
			
				|  |  | +			for (int c = 0; c < VU_HEIGHT; c++) {
 | 
	
		
			
				|  |  | +				GDS_DrawPixelFastExt(display, r + x, c + y, *data++ >> scale);
 | 
	
		
			
				|  |  | +			}	
 | 
	
		
			
				|  |  | +		}			
 | 
	
		
			
				|  |  |  	}	
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  |  	// need to manually set dirty flag as DrawPixel does not do it
 | 
	
	
		
			
				|  | @@ -613,22 +625,22 @@ static void grfe_handler( u8_t *data, int len) {
 | 
	
		
			
				|  |  |  	scroller.active = false;
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  |  	// visu has priority when full screen on small screens
 | 
	
		
			
				|  |  | -	if ((visu.mode & VISU_ESP32) && !visu.col && visu.row < SB_HEIGHT) {
 | 
	
		
			
				|  |  | +	if ((visu.mode & VISU_ESP32) && !visu.col && visu.row < displayer.height) {
 | 
	
		
			
				|  |  |  		xSemaphoreGive(displayer.mutex);
 | 
	
		
			
				|  |  |  		return;
 | 
	
		
			
				|  |  |  	}	
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  |  	// are we in control
 | 
	
		
			
				|  |  |  	if (displayer.owned) {
 | 
	
		
			
				|  |  | -		// did we have something that might have write on the bottom of a SB_HEIGHT+ display
 | 
	
		
			
				|  |  | -		if (displayer.dirty) {
 | 
	
		
			
				|  |  | -			GDS_ClearExt(display, true);
 | 
	
		
			
				|  |  | +		// draw new frame, it might be less than full screen (small visu)
 | 
	
		
			
				|  |  | +		int width = ((len - sizeof(struct grfe_packet)) * 8) / displayer.height;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		// did we have something that might have written on the bottom of a displayer's height + display
 | 
	
		
			
				|  |  | +		if (displayer.dirty || (artwork.enable && width == displayer.width && artwork.y < displayer.height)) {
 | 
	
		
			
				|  |  | +			GDS_Clear(display, GDS_COLOR_BLACK);
 | 
	
		
			
				|  |  |  			displayer.dirty = false;
 | 
	
		
			
				|  |  |  		}	
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  | -		// draw new frame, it might be less than full screen (small visu)
 | 
	
		
			
				|  |  | -		int width = ((len - sizeof(struct grfe_packet)) * 8) / displayer.height;
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  |  		// when doing screensaver, that frame becomes a visu background
 | 
	
		
			
				|  |  |  		if (!(visu.mode & VISU_ESP32)) {
 | 
	
		
			
				|  |  |  			visu.back.width = width;
 | 
	
	
		
			
				|  | @@ -735,7 +747,7 @@ static void grfg_handler(u8_t *data, int len) {
 | 
	
		
			
				|  |  |  	LOG_DEBUG("gfrg s:%hu w:%hu (len:%u)", htons(pkt->screen), htons(pkt->width), len);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	// on small screen, visu has priority when full screen	
 | 
	
		
			
				|  |  | -	if ((visu.mode & VISU_ESP32) && !visu.col && visu.row < SB_HEIGHT) return;
 | 
	
		
			
				|  |  | +	if ((visu.mode & VISU_ESP32) && !visu.col && visu.row < displayer.height) return;
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  |  	xSemaphoreTake(displayer.mutex, portMAX_DELAY);
 | 
	
		
			
				|  |  |  		
 | 
	
	
		
			
				|  | @@ -755,7 +767,7 @@ static void grfg_handler(u8_t *data, int len) {
 | 
	
		
			
				|  |  |  	}	
 | 
	
		
			
				|  |  |  		
 | 
	
		
			
				|  |  |  	// now we can active scrolling, but only if we are not on a small screen
 | 
	
		
			
				|  |  | -	if (!visu.mode || visu.col || visu.row >= SB_HEIGHT) scroller.active = true;
 | 
	
		
			
				|  |  | +	if (!visu.mode || visu.col || visu.row >= displayer.height) scroller.active = true;
 | 
	
		
			
				|  |  |  		
 | 
	
		
			
				|  |  |  	// if we just got a content update, let the scroller manage the screen
 | 
	
		
			
				|  |  |  	LOG_DEBUG("resuming scrolling task");
 | 
	
	
		
			
				|  | @@ -811,7 +823,7 @@ static void grfa_handler(u8_t *data, int len) {
 | 
	
		
			
				|  |  |  	artwork.size += size;
 | 
	
		
			
				|  |  |  	if (artwork.size == length) {
 | 
	
		
			
				|  |  |  		GDS_ClearWindow(display, artwork.x, artwork.y, -1, -1, GDS_COLOR_BLACK);
 | 
	
		
			
				|  |  | -		GDS_DrawJPEG(display, artwork.data, artwork.x, artwork.y, artwork.y < SB_HEIGHT ? (GDS_IMAGE_RIGHT | GDS_IMAGE_TOP) : GDS_IMAGE_CENTER);
 | 
	
		
			
				|  |  | +		GDS_DrawJPEG(display, artwork.data, artwork.x, artwork.y, artwork.y < displayer.height ? (GDS_IMAGE_RIGHT | GDS_IMAGE_TOP) : GDS_IMAGE_CENTER);
 | 
	
		
			
				|  |  |  		free(artwork.data);
 | 
	
		
			
				|  |  |  		artwork.data = NULL;
 | 
	
		
			
				|  |  |  	} 
 | 
	
	
		
			
				|  | @@ -852,7 +864,7 @@ static void visu_update(void) {
 | 
	
		
			
				|  |  |  		
 | 
	
		
			
				|  |  |  			// convert to dB (1 bit remaining for getting X²/N, 60dB dynamic starting from 0dBFS = 3 bits back-off)
 | 
	
		
			
				|  |  |  			for (int i = visu.n; --i >= 0;) {	 
 | 
	
		
			
				|  |  | -				visu.bars[i].current = SB_HEIGHT * (0.01667f*10*log10f(0.0000001f + (visu.bars[i].current >> 1)) - 0.2543f);
 | 
	
		
			
				|  |  | +				visu.bars[i].current = visu.max * (0.01667f*10*log10f(0.0000001f + (visu.bars[i].current >> (visu_export.gain == FIXED_ONE ? 7 : 1))) - 0.2543f);
 | 
	
		
			
				|  |  |  				if (visu.bars[i].current > visu.max) visu.bars[i].current = visu.max;
 | 
	
		
			
				|  |  |  				else if (visu.bars[i].current < 0) visu.bars[i].current = 0;
 | 
	
		
			
				|  |  |  			}
 | 
	
	
		
			
				|  | @@ -894,7 +906,7 @@ static void visu_update(void) {
 | 
	
		
			
				|  |  |  				}	
 | 
	
		
			
				|  |  |  			
 | 
	
		
			
				|  |  |  				// convert to dB and bars, same back-off
 | 
	
		
			
				|  |  | -				if (power) visu.bars[i].current = SB_HEIGHT * (0.01667f*10*(log10f(power) - log10f(FFT_LEN/2*2)) - 0.2543f);
 | 
	
		
			
				|  |  | +				if (power) visu.bars[i].current = visu.max * (0.01667f*10*(log10f(power) - log10f(FFT_LEN/(visu_export.gain == FIXED_ONE ? 128 : 2)*2)) - 0.2543f);
 | 
	
		
			
				|  |  |  				if (visu.bars[i].current > visu.max) visu.bars[i].current = visu.max;
 | 
	
		
			
				|  |  |  				else if (visu.bars[i].current < 0) visu.bars[i].current = 0;
 | 
	
		
			
				|  |  |  			}	
 | 
	
	
		
			
				|  | @@ -918,35 +930,49 @@ static void visu_update(void) {
 | 
	
		
			
				|  |  |  	if (mode != VISU_VUMETER || !visu.style) {
 | 
	
		
			
				|  |  |  		// there is much more optimization to be done here, like not redrawing bars unless needed
 | 
	
		
			
				|  |  |  		for (int i = visu.n; --i >= 0;) {
 | 
	
		
			
				|  |  | -			int x1 = visu.col + visu.border + visu.bar_border + i*(visu.bar_width + visu.bar_gap);
 | 
	
		
			
				|  |  | -			int y1 = visu.row + visu.height - 1;
 | 
	
		
			
				|  |  | -			
 | 
	
		
			
				|  |  | +			// update maximum
 | 
	
		
			
				|  |  |  			if (visu.bars[i].current > visu.bars[i].max) visu.bars[i].max = visu.bars[i].current;
 | 
	
		
			
				|  |  |  			else if (visu.bars[i].max) visu.bars[i].max--;
 | 
	
		
			
				|  |  |  			else if (!clear) continue;
 | 
	
		
			
				|  |  |  			
 | 
	
		
			
				|  |  | -			for (int j = 0; j <= visu.bars[i].current; j += 2) 
 | 
	
		
			
				|  |  | +			if (visu.rotate) {
 | 
	
		
			
				|  |  | +				int x1 = visu.col;
 | 
	
		
			
				|  |  | +				int y1 = visu.row + visu.border + visu.bar_border + i*(visu.bar_width + visu.bar_gap);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +				for (int j = 0; j <= visu.bars[i].current; j += 2) 
 | 
	
		
			
				|  |  | +					GDS_DrawLine(display, x1 + j, y1, x1 + j, y1 + visu.bar_width - 1, GDS_COLOR_WHITE);
 | 
	
		
			
				|  |  | +			
 | 
	
		
			
				|  |  | +				if (visu.bars[i].max > 2) {
 | 
	
		
			
				|  |  | +					GDS_DrawLine(display, x1 + visu.bars[i].max, y1, x1 + visu.bars[i].max, y1 + visu.bar_width - 1, GDS_COLOR_WHITE);			
 | 
	
		
			
				|  |  | +					if (visu.bars[i].max < visu.max - 1) GDS_DrawLine(display, x1 + visu.bars[i].max + 1, y1, x1 + visu.bars[i].max + 1, y1 + visu.bar_width - 1, GDS_COLOR_WHITE);			
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +			} else {
 | 
	
		
			
				|  |  | +				int x1 = visu.col + visu.border + visu.bar_border + i*(visu.bar_width + visu.bar_gap);
 | 
	
		
			
				|  |  | +				int y1 = visu.row + visu.height - 1;
 | 
	
		
			
				|  |  | +				for (int j = 0; j <= visu.bars[i].current; j += 2) 
 | 
	
		
			
				|  |  |  				GDS_DrawLine(display, x1, y1 - j, x1 + visu.bar_width - 1, y1 - j, GDS_COLOR_WHITE);
 | 
	
		
			
				|  |  |  			
 | 
	
		
			
				|  |  | -			if (visu.bars[i].max > 2) {
 | 
	
		
			
				|  |  | -				GDS_DrawLine(display, x1, y1 - visu.bars[i].max, x1 + visu.bar_width - 1, y1 - visu.bars[i].max, GDS_COLOR_WHITE);			
 | 
	
		
			
				|  |  | -				GDS_DrawLine(display, x1, y1 - visu.bars[i].max + 1, x1 + visu.bar_width - 1, y1 - visu.bars[i].max + 1, GDS_COLOR_WHITE);			
 | 
	
		
			
				|  |  | -			}	
 | 
	
		
			
				|  |  | +				if (visu.bars[i].max > 2) {
 | 
	
		
			
				|  |  | +					GDS_DrawLine(display, x1, y1 - visu.bars[i].max, x1 + visu.bar_width - 1, y1 - visu.bars[i].max, GDS_COLOR_WHITE);			
 | 
	
		
			
				|  |  | +					if (visu.bars[i].max < visu.max - 1) GDS_DrawLine(display, x1, y1 - visu.bars[i].max + 1, x1 + visu.bar_width - 1, y1 - visu.bars[i].max + 1, GDS_COLOR_WHITE);			
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	} else if (displayer.width / 2 >  3 * VU_WIDTH / 4) {
 | 
	
		
			
				|  |  | -		draw_VU(display, vu_bitmap, visu.bars[0].current, 0, visu.row, displayer.width / 2);
 | 
	
		
			
				|  |  | -		draw_VU(display, vu_bitmap, visu.bars[1].current, displayer.width / 2, visu.row, displayer.width / 2);
 | 
	
		
			
				|  |  | +		int width = visu.rotate ? visu.height : visu.width;
 | 
	
		
			
				|  |  | +		draw_VU(display, vu_bitmap, visu.bars[0].current, 0, visu.row, width / 2, visu.rotate);
 | 
	
		
			
				|  |  | +		draw_VU(display, vu_bitmap, visu.bars[1].current, width / 2, visu.row, width / 2, visu.rotate);
 | 
	
		
			
				|  |  |  	} else {
 | 
	
		
			
				|  |  |  		int level = (visu.bars[0].current + visu.bars[1].current) / 2;
 | 
	
		
			
				|  |  | -		draw_VU(display, vu_bitmap, level, 0, visu.row, displayer.width);		
 | 
	
		
			
				|  |  | +		draw_VU(display, vu_bitmap, level, 0, visu.row, visu.rotate ? visu.height : visu.width, visu.rotate);		
 | 
	
		
			
				|  |  |  	}	
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /****************************************************************************************
 | 
	
		
			
				|  |  | - * Visu packet handler
 | 
	
		
			
				|  |  | + * Calculate spectrum spread
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -void spectrum_limits(int min, int n, int pos) {
 | 
	
		
			
				|  |  | +static void spectrum_limits(int min, int n, int pos) {
 | 
	
		
			
				|  |  |  	if (n / 2) {
 | 
	
		
			
				|  |  |  		int step = ((DISPLAY_BW - min) * visu.spectrum_scale)  / (n/2);
 | 
	
		
			
				|  |  |  		visu.bars[pos].limit = min + step;
 | 
	
	
		
			
				|  | @@ -957,6 +983,29 @@ void spectrum_limits(int min, int n, int pos) {
 | 
	
		
			
				|  |  |  	}	
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/****************************************************************************************
 | 
	
		
			
				|  |  | + * Fit visu
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static void visu_fit(int bars, int width, int height) {
 | 
	
		
			
				|  |  | +	// try to adapt to what we have
 | 
	
		
			
				|  |  | +	if ((visu.mode & ~VISU_ESP32) == VISU_SPECTRUM) {
 | 
	
		
			
				|  |  | +		visu.n = bars ? bars : MAX_BARS;
 | 
	
		
			
				|  |  | +		visu.max = height - 1;
 | 
	
		
			
				|  |  | +		if (visu.spectrum_scale <= 0 || visu.spectrum_scale > 0.5) visu.spectrum_scale = 0.5;
 | 
	
		
			
				|  |  | +		spectrum_limits(0, visu.n, 0);
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		visu.n = 2;
 | 
	
		
			
				|  |  | +		visu.max = (visu.style ? VU_COUNT : height) - 1;
 | 
	
		
			
				|  |  | +	}	
 | 
	
		
			
				|  |  | +		
 | 
	
		
			
				|  |  | +	do {
 | 
	
		
			
				|  |  | +		visu.bar_width = (width - visu.border - visu.bar_gap * (visu.n - 1)) / visu.n;
 | 
	
		
			
				|  |  | +		if (visu.bar_width > 0) break;
 | 
	
		
			
				|  |  | +	} while (--visu.n);	
 | 
	
		
			
				|  |  | +	
 | 
	
		
			
				|  |  | +	visu.bar_border = (width - visu.border - (visu.bar_width + visu.bar_gap) * visu.n + visu.bar_gap) / 2;
 | 
	
		
			
				|  |  | +}	
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /****************************************************************************************
 | 
	
		
			
				|  |  |   * Visu packet handler
 | 
	
		
			
				|  |  |   */
 | 
	
	
		
			
				|  | @@ -976,12 +1025,12 @@ static void visu_handler( u8_t *data, int len) {
 | 
	
		
			
				|  |  |  	visu.mode = pkt->which;
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  |  	// little trick to clean the taller screens when switching visu 
 | 
	
		
			
				|  |  | -	if (visu.row >= SB_HEIGHT) GDS_ClearExt(display, false, true, visu.col, visu.row, visu.col + visu.width - 1, visu.row + visu.height - 1);
 | 
	
		
			
				|  |  | +	if (visu.row >= displayer.height) GDS_ClearExt(display, false, true, visu.col, visu.row, visu.col + visu.width - 1, visu.row + visu.height - 1);
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  |  	if (visu.mode) {
 | 
	
		
			
				|  |  |  		// these will be overidden if necessary
 | 
	
		
			
				|  |  |  		visu.col = visu.border = 0;
 | 
	
		
			
				|  |  | -		visu.width = displayer.width;				
 | 
	
		
			
				|  |  | +		visu.rotate = false;
 | 
	
		
			
				|  |  |  		
 | 
	
		
			
				|  |  |  		// what type of visu
 | 
	
		
			
				|  |  |  		if (visu.mode & VISU_ESP32) {
 | 
	
	
		
			
				|  | @@ -993,7 +1042,7 @@ static void visu_handler( u8_t *data, int len) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  				visu.style = 0;
 | 
	
		
			
				|  |  |  				visu.width = htonl(pkt->width);
 | 
	
		
			
				|  |  | -				visu.height = pkt->height ? pkt->height : SB_HEIGHT;
 | 
	
		
			
				|  |  | +				visu.height = pkt->height ? pkt->height : displayer.height;
 | 
	
		
			
				|  |  |  				visu.col = pkt->col < 0 ? displayer.width + pkt->col : pkt->col;
 | 
	
		
			
				|  |  |  				visu.row = pkt->row < 0 ? GDS_GetHeight(display) + pkt->row : pkt->row;
 | 
	
		
			
				|  |  |  				visu.border =  htonl(pkt->border);
 | 
	
	
		
			
				|  | @@ -1001,9 +1050,13 @@ static void visu_handler( u8_t *data, int len) {
 | 
	
		
			
				|  |  |  				visu.spectrum_scale = htonl(pkt->spectrum_scale) / 100.;
 | 
	
		
			
				|  |  |  			} else {
 | 
	
		
			
				|  |  |  				// full screen visu, try to use bottom screen if available
 | 
	
		
			
				|  |  | -				visu.height = GDS_GetHeight(display) > SB_HEIGHT ? GDS_GetHeight(display) - SB_HEIGHT : GDS_GetHeight(display);
 | 
	
		
			
				|  |  | +				visu.width = htonl(pkt->full.width);
 | 
	
		
			
				|  |  | +				visu.height = GDS_GetHeight(display) > displayer.height ? GDS_GetHeight(display) - displayer.height : GDS_GetHeight(display);
 | 
	
		
			
				|  |  |  				visu.row = GDS_GetHeight(display) - visu.height;			
 | 
	
		
			
				|  |  |  				
 | 
	
		
			
				|  |  | +				// try to estimate if we should rotate visu
 | 
	
		
			
				|  |  | +				if (visu.height > displayer.height && visu.height > 2*visu.width) visu.rotate = true;
 | 
	
		
			
				|  |  | +				
 | 
	
		
			
				|  |  |  				// is this spectrum or analogue/digital
 | 
	
		
			
				|  |  |  				if ((visu.mode & ~VISU_ESP32) == VISU_SPECTRUM) {
 | 
	
		
			
				|  |  |  					bars = htonl(pkt->full.bars);
 | 
	
	
		
			
				|  | @@ -1016,37 +1069,29 @@ static void visu_handler( u8_t *data, int len) {
 | 
	
		
			
				|  |  |  		} else {
 | 
	
		
			
				|  |  |  			// classical (screensaver) mode, don't try to optimize screen usage & force some params
 | 
	
		
			
				|  |  |  			visu.row = 0;
 | 
	
		
			
				|  |  | -			visu.height = SB_HEIGHT;
 | 
	
		
			
				|  |  | +			visu.height = GDS_GetHeight(display);
 | 
	
		
			
				|  |  | +			visu.width = displayer.width;				
 | 
	
		
			
				|  |  |  			visu.spectrum_scale = 0.25;				
 | 
	
		
			
				|  |  | -			if (visu.mode == VISU_SPECTRUM) bars = visu.width / (htonl(pkt->channels[0].bar_width) + htonl(pkt->channels[0].bar_space));
 | 
	
		
			
				|  |  | -			else visu.style = htonl(pkt->classical_vu.style);
 | 
	
		
			
				|  |  | +			if (visu.mode == VISU_SPECTRUM) {
 | 
	
		
			
				|  |  | +				bars = visu.width / (htonl(pkt->channels[0].bar_width) + htonl(pkt->channels[0].bar_space));
 | 
	
		
			
				|  |  | +			} else {
 | 
	
		
			
				|  |  | +				visu.style = htonl(pkt->classical_vu.style);
 | 
	
		
			
				|  |  | +				if (visu.style) visu.row = visu.height - VU_HEIGHT;
 | 
	
		
			
				|  |  | +			}	
 | 
	
		
			
				|  |  |  			if (bars > MAX_BARS) bars = MAX_BARS;
 | 
	
		
			
				|  |  |  		}	
 | 
	
		
			
				|  |  |  		
 | 
	
		
			
				|  |  | -		// try to adapt to what we have
 | 
	
		
			
				|  |  | -		if ((visu.mode & ~VISU_ESP32) == VISU_SPECTRUM) {
 | 
	
		
			
				|  |  | -			visu.n = bars ? bars : MAX_BARS;
 | 
	
		
			
				|  |  | -			visu.max = displayer.height - 1;
 | 
	
		
			
				|  |  | -			if (visu.spectrum_scale <= 0 || visu.spectrum_scale > 0.5) visu.spectrum_scale = 0.5;
 | 
	
		
			
				|  |  | -			spectrum_limits(0, visu.n, 0);
 | 
	
		
			
				|  |  | -		} else {
 | 
	
		
			
				|  |  | -			visu.n = 2;
 | 
	
		
			
				|  |  | -			visu.max = visu.style ? (VU_COUNT - 1) : (displayer.height - 1);
 | 
	
		
			
				|  |  | -		}	
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		do {
 | 
	
		
			
				|  |  | -			visu.bar_width = (visu.width - visu.border - visu.bar_gap * (visu.n - 1)) / visu.n;
 | 
	
		
			
				|  |  | -			if (visu.bar_width > 0) break;
 | 
	
		
			
				|  |  | -		} while (--visu.n);	
 | 
	
		
			
				|  |  | -		visu.bar_border = (visu.width - visu.border - (visu.bar_width + visu.bar_gap) * visu.n + visu.bar_gap) / 2;
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | +		// for rotate, swap width & height
 | 
	
		
			
				|  |  | +		if (visu.rotate) visu_fit(bars, visu.height, visu.width);
 | 
	
		
			
				|  |  | +		else visu_fit(bars, visu.width, visu.height);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  		// give up if not enough space
 | 
	
		
			
				|  |  |  		if (visu.bar_width < 0)	{
 | 
	
		
			
				|  |  |  			visu.mode = VISU_BLANK;
 | 
	
		
			
				|  |  |  			LOG_WARN("Not enough room for displaying visu");
 | 
	
		
			
				|  |  |  		} else {
 | 
	
		
			
				|  |  |  			// de-activate scroller if we are taking main screen
 | 
	
		
			
				|  |  | -			if (visu.row < SB_HEIGHT) scroller.active = false;
 | 
	
		
			
				|  |  | +			if (visu.row < displayer.height) scroller.active = false;
 | 
	
		
			
				|  |  |  			vTaskResume(displayer.task);
 | 
	
		
			
				|  |  |  		}	
 | 
	
		
			
				|  |  |  		visu.wake = 0;
 |