Forráskód Böngészése

handle "generic" visualizer - release

philippe44 5 éve
szülő
commit
ff40290610

+ 125 - 30
components/squeezelite/display.c

@@ -86,6 +86,29 @@ struct visu_packet {
 			u32_t bars;
 			u32_t spectrum_scale;
 		};	
+		struct {
+			u32_t mono;
+			u32_t bandwidth;
+			u32_t preemph;	
+			struct {
+				u32_t pos;
+				u32_t width;
+				u32_t orient;
+				u32_t bar_width;
+				u32_t bar_space;
+				u32_t clipping;
+				u32_t bar_intens;
+				u32_t bar_cap_intens;
+			} channels[2];
+		};
+		struct {
+			u32_t mono;
+			u32_t style;
+			struct {
+				u32_t pos;
+				u32_t width;
+			} channels[2];
+		} classical_vu;	
 	};	
 };
 
@@ -143,9 +166,11 @@ static struct {
 	u8_t *data;
 	u32_t size;
 	u16_t x, y;
+	bool enable;
 } artwork;
 
 #define MAX_BARS	32
+#define VISU_ESP32	0x10
 static EXT_RAM_ATTR struct {
 	int bar_gap, bar_width, bar_border;
 	struct {
@@ -157,6 +182,11 @@ static EXT_RAM_ATTR struct {
 	enum { VISU_BLANK, VISU_VUMETER, VISU_SPECTRUM, VISU_WAVEFORM } mode;
 	int speed, wake;	
 	float fft[FFT_LEN*2], samples[FFT_LEN*2], hanning[FFT_LEN];
+	struct {
+		u8_t *frame;
+		int width;
+		bool active;
+	} back;		
 } visu;
 
 #define ANIM_NONE		  0x00
@@ -221,6 +251,33 @@ static void displayer_task(void* arg);
 			ANIM_SCREEN_2     0x08 # For scrollonce only, screen 2 was scrolling
 */
 
+/* classical visu not our specific version)
+ Parameters for the spectrum analyzer:
+   0 - Channels: stereo == 0, mono == 1
+   1 - Bandwidth: 0..22050Hz == 0, 0..11025Hz == 1
+   2 - Preemphasis in dB per KHz
+ Left channel parameters:
+   3 - Position in pixels
+   4 - Width in pixels
+   5 - orientation: left to right == 0, right to left == 1
+   6 - Bar width in pixels
+   7 - Bar spacing in pixels
+   8 - Clipping: show all subbands == 0, clip higher subbands == 1
+   9 - Bar intensity (greyscale): 1-3
+   10 - Bar cap intensity (greyscale): 1-3
+ Right channel parameters (not required for mono):
+   11-18 - same as left channel parameters
+
+ Parameters for the vumeter:
+   0 - Channels: stereo == 0, mono == 1
+   1 - Style: digital == 0, analog == 1
+ Left channel parameters:
+   2 - Position in pixels
+   3 - Width in pixels
+ Right channel parameters (not required for mono):
+   4-5 - same as left channel parameters
+*/
+
 /****************************************************************************************
  * 
  */
@@ -242,6 +299,7 @@ bool sb_display_init(void) {
 	// create visu configuration
 	visu.bar_gap = 1;
 	visu.speed = 100;
+	visu.back.frame = calloc(1, (displayer.width * displayer.height) / 8);
 	dsps_fft2r_init_fc32(visu.fft, FFT_LEN);
 	dsps_wind_hann_f32(visu.hanning, FFT_LEN);
 		
@@ -517,7 +575,7 @@ static void grfe_handler( u8_t *data, int len) {
 	scroller.active = false;
 	
 	// we are not in control or we are displaying visu on a small screen, do not do screen update
-	if (visu.mode && !visu.col && visu.row < SB_HEIGHT) {
+	if ((visu.mode & VISU_ESP32) && !visu.col && visu.row < SB_HEIGHT) {
 		xSemaphoreGive(displayer.mutex);
 		return;
 	}	
@@ -531,6 +589,16 @@ static void grfe_handler( u8_t *data, int len) {
 	
 		// 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;
+			memset(visu.back.frame, 0, (displayer.width * displayer.height) / 8);
+			memcpy(visu.back.frame, data + sizeof(struct grfe_packet), (width * displayer.height) / 8);
+			// this is a bit tricky but basically that checks if frame if full of 0
+			visu.back.active = *visu.back.frame || memcmp(visu.back.frame, visu.back.frame + 1, width - 1);
+		}
+		
 		GDS_DrawBitmapCBR(display, data + sizeof(struct grfe_packet), width, displayer.height, GDS_COLOR_WHITE);
 		GDS_Update(display);
 	}	
@@ -570,7 +638,7 @@ static void grfs_handler(u8_t *data, int len) {
 	int size = len - sizeof(struct grfs_packet);
 	int offset = htons(pkt->offset);
 	
-	LOG_DEBUG("gfrs s:%u d:%u p:%u sp:%u by:%hu m:%hu w:%hu o:%hu", 
+	LOG_DEBUG("grfs s:%u d:%u p:%u sp:%u by:%hu m:%hu w:%hu o:%hu", 
 				(int) pkt->screen,
 				(int) pkt->direction,	// 1=left, 2=right
 				htonl(pkt->pause),		// in ms	
@@ -666,6 +734,14 @@ static void grfa_handler(u8_t *data, int len) {
 	int offset = htonl(pkt->offset);
 	int length = htonl(pkt->length);
 	
+	artwork.enable = (length != 0);
+	
+	// clean up if we are disabling previously enabled artwork
+	if (!artwork.enable) {
+		if (artwork.size) GDS_ClearWindow(display, artwork.x, artwork.y, -1, -1, GDS_COLOR_BLACK);
+		return;
+	}	
+	
 	// new grfa artwork, allocate memory
 	if (!offset) {	
 		// same trick to clean current/previous window
@@ -679,7 +755,6 @@ static void grfa_handler(u8_t *data, int len) {
 		artwork.y = htons(pkt->y);
 		if (artwork.data) free(artwork.data);
 		artwork.data = malloc(length);
-		artwork.size = 0;
 	}	
 	
 	// copy artwork data
@@ -687,7 +762,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 < 32 ? (GDS_IMAGE_RIGHT | GDS_IMAGE_TOP) : GDS_IMAGE_CENTER);
+		GDS_DrawJPEG(display, artwork.data, artwork.x, artwork.y, artwork.y < SB_HEIGHT ? (GDS_IMAGE_RIGHT | GDS_IMAGE_TOP) : GDS_IMAGE_CENTER);
 		free(artwork.data);
 		artwork.data = NULL;
 	} 
@@ -701,9 +776,11 @@ static void grfa_handler(u8_t *data, int len) {
 static void visu_update(void) {
 	// no need to protect against no woning the display as we are playing	
 	if (pthread_mutex_trylock(&visu_export.mutex)) return;
+	
+	int mode = visu.mode & ~VISU_ESP32;
 				
 	// not enough samples
-	if (visu_export.level < (visu.mode == VISU_VUMETER ? RMS_LEN : FFT_LEN) * 2 && visu_export.running) {
+	if (visu_export.level < (mode == VISU_VUMETER ? RMS_LEN : FFT_LEN) * 2 && visu_export.running) {
 		pthread_mutex_unlock(&visu_export.mutex);
 		return;
 	}
@@ -713,7 +790,7 @@ static void visu_update(void) {
 	
 	if (visu_export.running) {
 					
-		if (visu.mode == VISU_VUMETER) {
+		if (mode == VISU_VUMETER) {
 			s16_t *iptr = visu_export.buffer;
 			
 			// calculate sum(L²+R²), try to not overflow at the expense of some precision
@@ -726,7 +803,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 = 32 * (0.01667f*10*log10f(0.0000001f + (visu.bars[i].current >> 1)) - 0.2543f);
+				visu.bars[i].current = SB_HEIGHT * (0.01667f*10*log10f(0.0000001f + (visu.bars[i].current >> 1)) - 0.2543f);
 				if (visu.bars[i].current > 31) visu.bars[i].current = 31;
 				else if (visu.bars[i].current < 0) visu.bars[i].current = 0;
 			}
@@ -768,7 +845,7 @@ static void visu_update(void) {
 				}	
 			
 				// convert to dB and bars, same back-off
-				if (power) visu.bars[i].current = 32 * (0.01667f*10*(log10f(power) - log10f(FFT_LEN/2*2)) - 0.2543f);
+				if (power) visu.bars[i].current = SB_HEIGHT * (0.01667f*10*(log10f(power) - log10f(FFT_LEN/2*2)) - 0.2543f);
 				if (visu.bars[i].current > 31) visu.bars[i].current = 31;
 				else if (visu.bars[i].current < 0) visu.bars[i].current = 0;
 			}	
@@ -783,6 +860,11 @@ static void visu_update(void) {
 	int clear = 0;
 	for (int i = visu.n; --i >= 0;) clear = max(clear, visu.bars[i].max);
 	if (clear) GDS_ClearExt(display, false, false, visu.col, visu.row, visu.col + visu.width - 1, visu.row + visu.height - 1);
+	
+	// draw background if we are in screensaver mode
+	if (!(visu.mode & VISU_ESP32) && visu.back.active) {
+		GDS_DrawBitmapCBR(display, visu.back.frame, visu.back.width, displayer.height, GDS_COLOR_WHITE);
+	}	
 
 	// there is much more optimization to be done here, like not redrawing bars unless needed
 	for (int i = visu.n; --i >= 0;) {
@@ -840,31 +922,44 @@ static void visu_handler( u8_t *data, int len) {
 	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.mode) {
-		if (pkt->count >= 4) {
-			// small visu, then go were we are told to
-			pkt->height = htonl(pkt->height);
-			pkt->row = htonl(pkt->row);
-			pkt->col = htonl(pkt->col);
-
-			visu.width = htonl(pkt->width);
-			visu.height = pkt->height ? pkt->height : SB_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);
-			bars = htonl(pkt->bars);
-			visu.spectrum_scale = htonl(pkt->spectrum_scale) / 100.;
+		// these will be overidden if necessary
+		visu.col = visu.border = 0;
+		visu.width = displayer.width;				
+		
+		// what type of visu
+		if (visu.mode & VISU_ESP32) {
+			if (pkt->count >= 4) {
+				// more than 4 parameters, this is small visu, then go were we are told to
+				pkt->height = htonl(pkt->height);
+				pkt->row = htonl(pkt->row);
+				pkt->col = htonl(pkt->col);
+
+				visu.width = htonl(pkt->width);
+				visu.height = pkt->height ? pkt->height : SB_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);
+				bars = htonl(pkt->bars);
+				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);
+				bars = htonl(pkt->full.bars);
+				visu.spectrum_scale = htonl(pkt->full.spectrum_scale) / 100.;
+				visu.row = GDS_GetHeight(display) - visu.height;			
+			}	
 		} else {
-			// full screen visu, try to use bottom screen if available
-			visu.width = displayer.width;
-			visu.height = GDS_GetHeight(display) > SB_HEIGHT ? GDS_GetHeight(display) - SB_HEIGHT : GDS_GetHeight(display);
-			visu.col = visu.border = 0;
-			visu.row = GDS_GetHeight(display) - visu.height;			
-			bars = htonl(pkt->full.bars);
-			visu.spectrum_scale = htonl(pkt->full.spectrum_scale) / 100.;
-		}
+			// classical (screensaver) mode, don't try to optimize screen usage & force some params
+			visu.row = 0;
+			visu.height = SB_HEIGHT;
+			visu.spectrum_scale = 0.25;				
+			if (artwork.enable && artwork.y < SB_HEIGHT) visu.width = artwork.x - 1;
+			if (visu.mode == VISU_SPECTRUM) bars = visu.width / (htonl(pkt->channels[0].bar_width) + htonl(pkt->channels[0].bar_space));
+			if (bars > MAX_BARS) bars = MAX_BARS;
+		}	
 		
 		// try to adapt to what we have
-		if (visu.mode == VISU_SPECTRUM) {
+		if ((visu.mode & ~VISU_ESP32) == VISU_SPECTRUM) {
 			visu.n = bars ? bars : MAX_BARS;
 			if (visu.spectrum_scale <= 0 || visu.spectrum_scale > 0.5) visu.spectrum_scale = 0.5;
 			spectrum_limits(0, visu.n, 0);

BIN
plugin/SqueezeESP32.zip


+ 13 - 11
plugin/SqueezeESP32/Graphics.pm

@@ -14,6 +14,8 @@ my $VISUALIZER_NONE = 0;
 my $VISUALIZER_VUMETER = 1;
 my $VISUALIZER_SPECTRUM_ANALYZER = 2;
 my $VISUALIZER_WAVEFORM = 3;
+my $VISUALIZER_VUMETER_ESP32 = 0x11;
+my $VISUALIZER_SPECTRUM_ANALYZER_ESP32 = 0x12;
 
 {
 	#__PACKAGE__->mk_accessor('array', 'modes');
@@ -72,7 +74,7 @@ sub displayWidth {
 	
 	if ($display->widthOverride) {
 		my $artwork = $prefs->client($client)->get('artwork');
-		if ($artwork->{'enable'} && $artwork->{'y'} < 32) {
+		if ($artwork->{'enable'} && $artwork->{'y'} < 32 && $client->isPlaying) {
 			return $artwork->{x} + ($display->modes->[$mode || 0]{_width} || 0);
 		} else {
 			return $display->widthOverride + ($display->modes->[$mode || 0]{_width} || 0);
@@ -105,7 +107,7 @@ sub build_modes {
 	my $client = shift->client;
 	my $cprefs = $prefs->client($client);
 	
-	my $width = shift || $cprefs->get('width') || 128;
+	my $width = $cprefs->get('width') || 128;
 	my $artwork = $cprefs->get('artwork');
 	
 	# if artwork is in main display, reduce width
@@ -154,39 +156,39 @@ sub build_modes {
 		{ desc => ['VISUALIZER_VUMETER_SMALL'],
 		bar => 0, secs => 0,  width => $width, _width => -$small_VU_pos->{'width'},
 		# extra parameters (width, height, col (< 0 = from right), row (< 0 = from bottom), left_space)
-		params => [$VISUALIZER_VUMETER, $small_VU_pos->{'width'}, 32, $small_VU_pos->{'x'}, 0, 2] },
+		params => [$VISUALIZER_VUMETER_ESP32, $small_VU_pos->{'width'}, 32, $small_VU_pos->{'x'}, 0, 2] },
 		# mode 8
 		{ desc => ['VISUALIZER_SPECTRUM_ANALYZER_SMALL'],
 		bar => 0, secs => 0,  width => $width, _width => -$small_spectrum_pos->{'width'},
-		# extra parameters (width, height, col (< 0 = from right), row (< 0 = from bottom), left_space, bars)
-		params => [$VISUALIZER_SPECTRUM_ANALYZER, $small_spectrum_pos->{width}, 32, $small_spectrum_pos->{'x'}, 0, 2, $small_spectrum_pos->{'width'} / $spectrum->{small}->{band}, $spectrum->{scale}] },  
+		# extra parameters (width, height, col (< 0 = from right), row (< 0 = from bottom), left_space, #bars, scale)
+		params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $small_spectrum_pos->{width}, 32, $small_spectrum_pos->{'x'}, 0, 2, $small_spectrum_pos->{'width'} / $spectrum->{small}->{band}, $spectrum->{scale}] },  
 		# mode 9	 
 		{ desc => ['VISUALIZER_VUMETER'],
 		bar => 0, secs => 0,  width => $width,
-		params => [$VISUALIZER_VUMETER] },
+		params => [$VISUALIZER_VUMETER_ESP32] },
 		# mode 10
 		{ desc => ['VISUALIZER_SPECTRUM_ANALYZER'],
 		bar => 0, secs => 0,  width => $width,
 		# extra parameters (bars)
-		params => [$VISUALIZER_SPECTRUM_ANALYZER, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] },	  
+		params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] },	  
 		# mode 11	 
 		{ desc => ['VISUALIZER_VUMETER', 'AND', 'ELAPSED'],
 		bar => 0, secs => 1,  width => $width,
-		params => [$VISUALIZER_VUMETER] },
+		params => [$VISUALIZER_VUMETER_ESP32] },
 		# mode 12
 		{ desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'ELAPSED'],
 		bar => 0, secs => 1,  width => $width,
 		# extra parameters (bars)
-		params => [$VISUALIZER_SPECTRUM_ANALYZER, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] },	  
+		params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] },	  
 		# mode 13	 
 		{ desc => ['VISUALIZER_VUMETER', 'AND', 'REMAINING'],
 		bar => 0, secs => -1,  width => $width,
-		params => [$VISUALIZER_VUMETER] },
+		params => [$VISUALIZER_VUMETER_ESP32] },
 		# mode 14
 		{ desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'REMAINING'],
 		bar => 0, secs => -1,  width => $width,
 		# extra parameters (bars)
-		params => [$VISUALIZER_SPECTRUM_ANALYZER, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] },	
+		params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] },	
 	);
 	
 	return \@modes;

+ 2 - 8
plugin/SqueezeESP32/Player.pm

@@ -26,7 +26,7 @@ sub playerSettingsFrame {
 		$value = (unpack('Cn', $$data_ref))[1];
 		if ($value > 100 && $value < 400) {
 			$prefs->client($client)->set('width', $value);
-			$client->display->modes($client->display->build_modes($value));
+			$client->display->modes($client->display->build_modes);
 			$client->display->widthOverride(1, $value);
 			$client->update;
 		} 
@@ -38,7 +38,7 @@ sub playerSettingsFrame {
 	$client->SUPER::playerSettingsFrame($data_ref);
 }
 
-sub hasScrolling  {
+sub hasScrolling {
 	return 1;
 }
 
@@ -48,10 +48,4 @@ sub reconnect {
 	$client->SUPER::reconnect(@_);
 }	
 
-sub directMetadata {
-	my $client = shift;
-	$client->SUPER::directMetadata(@_);
-	Slim::Control::Request::notifyFromArray( $client, [ 'newmetadata' ] );
-}
-
 1;

+ 6 - 2
plugin/SqueezeESP32/PlayerSettings.pm

@@ -55,8 +55,12 @@ sub handler {
 		$client->display->modes($client->display->build_modes);
 		$client->display->update;
 		
-		# force update
-		Plugins::SqueezeESP32::Plugin::update_artwork($client, 1) if $artwork->{'enable'};
+		# force update or disable artwork
+		if ($artwork->{'enable'}) {
+			Plugins::SqueezeESP32::Plugin::update_artwork($client, 1);
+		} else {
+			Plugins::SqueezeESP32::Plugin::disable_artwork($client);
+		}	
 	}
 	
 	# as there is nothing captured, we need to re-set these variables

+ 6 - 0
plugin/SqueezeESP32/Plugin.pm

@@ -95,4 +95,10 @@ sub send_artwork {
 	}
 }	
 
+sub disable_artwork {
+	my ($client) = @_;
+	my $header = pack('N', 0);
+	$client->sendFrame( grfa => \$header );
+}
+
 1;

+ 1 - 1
plugin/SqueezeESP32/install.xml

@@ -10,6 +10,6 @@
   <name>PLUGIN_SQUEEZEESP32</name>
   <description>PLUGIN_SQUEEZEESP32_DESC</description>
   <module>Plugins::SqueezeESP32::Plugin</module>
-    <version>0.43</version>
+    <version>0.50</version>
   <creator>Philippe</creator>
 </extensions>

+ 2 - 2
plugin/repo.xml

@@ -1,10 +1,10 @@
 <?xml version='1.0' standalone='yes'?>
 <extensions>
   <plugins>
-    <plugin version="0.43" name="SqueezeESP32" minTarget="7.5" maxTarget="*">
+    <plugin version="0.50" name="SqueezeESP32" minTarget="7.5" maxTarget="*">
       <link>https://github.com/sle118/squeezelite-esp32</link>
       <creator>Philippe</creator>
-      <sha>3460f07b43dcdb2cbdf4d10e6536da7abd87b3a1</sha>
+      <sha>47feaf69a40ad4f87c58b34212d71e60dca99d3e</sha>
       <email>philippe_44@outlook.com</email>
       <desc lang="EN">SqueezeESP32 additional player id (100)</desc>
       <url>http://github.com/sle118/squeezelite-esp32/raw/master/plugin/SqueezeESP32.zip</url>