From 26330ee69e91ba3f92e42f220a68646a78b95846 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Wed, 1 Apr 2020 20:03:57 -0700 Subject: [PATCH 1/5] add SSD1322 + few tweaks - release --- components/display/SSD1322.c | 203 +++++++++++++++++++++++++++++++ components/display/display.c | 4 +- components/squeezelite/display.c | 68 ++++++----- plugin/SqueezeESP32.zip | Bin 8209 -> 8316 bytes plugin/SqueezeESP32/Graphics.pm | 33 +++-- plugin/SqueezeESP32/Plugin.pm | 17 ++- plugin/SqueezeESP32/install.xml | 2 +- plugin/repo.xml | 4 +- 8 files changed, 284 insertions(+), 47 deletions(-) create mode 100644 components/display/SSD1322.c diff --git a/components/display/SSD1322.c b/components/display/SSD1322.c new file mode 100644 index 00000000..ea449aea --- /dev/null +++ b/components/display/SSD1322.c @@ -0,0 +1,203 @@ +/** + * Copyright (c) 2017-2018 Tara Keeling + * 2020 Philippe G. + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include +#include +#include +#include +#include +#include + +#include "gds.h" +#include "gds_private.h" + +#define SHADOW_BUFFER +#define PAGE_BLOCK 1024 + +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +static char TAG[] = "SSD1322"; + +struct PrivateSpace { + uint8_t *iRAM, *Shadowbuffer; + uint8_t ReMap, PageSize; + uint8_t Offset; +}; + +// Functions are not declared to minimize # of lines + +static void WriteDataByte( struct GDS_Device* Device, uint8_t Data ) { + Device->WriteData( Device, &Data, 1); +} + +static void SetColumnAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) { + Device->WriteCommand( Device, 0x15 ); + Device->WriteData( Device, &Start, 1 ); + Device->WriteData( Device, &End, 1 ); +} +static void SetRowAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) { + Device->WriteCommand( Device, 0x75 ); + Device->WriteData( Device, &Start, 1 ); + Device->WriteData( Device, &End, 1 ); +} + +static void Update( struct GDS_Device* Device ) { + struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private; + + // RAM is by columns of 4 pixels ... + SetColumnAddress( Device, Private->Offset, Private->Offset + Device->Width / 4 - 1); + +#ifdef SHADOW_BUFFER + uint16_t *optr = (uint16_t*) Private->Shadowbuffer, *iptr = (uint16_t*) Device->Framebuffer; + bool dirty = false; + + for (int r = 0, page = 0; r < Device->Height; r++) { + // look for change and update shadow (cheap optimization = width always / by 2) + for (int c = Device->Width / 2 / 2; --c >= 0;) { + if (*optr != *iptr) { + dirty = true; + *optr = *iptr; + } + iptr++; optr++; + } + + // one line done, check for page boundary + if (++page == Private->PageSize) { + if (dirty) { + uint16_t *optr = (uint16_t*) Private->iRAM, *iptr = (uint16_t*) (Private->Shadowbuffer + (r - page + 1) * Device->Width / 2); + SetRowAddress( Device, r - page + 1, r ); + for (int i = page * Device->Width / 2 / 2; --i >= 0; iptr++) *optr++ = (*iptr >> 8) | (*iptr << 8); + //memcpy(Private->iRAM, Private->Shadowbuffer + (r - page + 1) * Device->Width / 2, page * Device->Width / 2 ); + Device->WriteCommand( Device, 0x5c ); + Device->WriteData( Device, Private->iRAM, Device->Width * page / 2 ); + dirty = false; + } + page = 0; + } + } +#else + for (int r = 0; r < Device->Height; r += Private->PageSize) { + SetRowAddress( Device, r, r + Private->PageSize - 1 ); + Device->WriteCommand( Device, 0x5c ); + if (Private->iRAM) { + uint16_t *optr = (uint16_t*) Private->iRAM, *iptr = (uint16_t*) (Device->Framebuffer + r * Device->Width / 2); + for (int i = Private->PageSize * Device->Width / 2 / 2; --i >= 0; iptr++) *optr++ = (*iptr >> 8) | (*iptr << 8); + //memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 ); + Device->WriteData( Device, Private->iRAM, Private->PageSize * Device->Width / 2 ); + } else { + Device->WriteData( Device, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 ); + } + } +#endif +} + +static void SetHFlip( struct GDS_Device* Device, bool On ) { + struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private; + Private->ReMap = On ? (Private->ReMap & ~(1 << 1)) : (Private->ReMap | (1 << 1)); + Device->WriteCommand( Device, 0xA0 ); + Device->WriteData( Device, &Private->ReMap, 1 ); + WriteDataByte( Device, 0x11 ); +} + +static void SetVFlip( struct GDS_Device *Device, bool On ) { + struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private; + Private->ReMap = On ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4)); + Device->WriteCommand( Device, 0xA0 ); + Device->WriteData( Device, &Private->ReMap, 1 ); + WriteDataByte( Device, 0x11 ); +} + +static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); } +static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); } + +static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) { + Device->WriteCommand( Device, 0xC1 ); + Device->WriteData( Device, &Contrast, 1 ); +} + +static bool Init( struct GDS_Device* Device ) { + struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private; + + // these displays seems to be layout centered (1 column = 4 pixels of 4 bits each, little endian) + Private->Offset = (480 - Device->Width) / 4 / 2; + + // find a page size that is not too small is an integer of height + Private->PageSize = min(8, PAGE_BLOCK / (Device->Width / 2)); + Private->PageSize = Device->Height / (Device->Height / Private->PageSize) ; + +#ifdef SHADOW_BUFFER + Private->Shadowbuffer = malloc( Device->FramebufferSize ); + memset(Private->Shadowbuffer, 0xFF, Device->FramebufferSize); +#endif + Private->iRAM = heap_caps_malloc( Private->PageSize * Device->Width / 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA ); + + ESP_LOGI(TAG, "SSD1322 with offset %u, page %u, iRAM %p", Private->Offset, Private->PageSize, Private->iRAM); + + // need to be off and disable display RAM + Device->DisplayOff( Device ); + Device->WriteCommand( Device, 0xA5 ); + + // Display Offset + Device->WriteCommand( Device, 0xA2 ); + WriteDataByte( Device, 0 ); + + // Display Start Line + Device->WriteCommand( Device, 0xA1 ); + WriteDataByte( Device, 0x00 ); + + // set flip modes + Private->ReMap = 0; + Device->SetVFlip( Device, false ); + Device->SetHFlip( Device, false ); + + // set Clocks + Device->WriteCommand( Device, 0xB3 ); + WriteDataByte( Device, 0x91 ); + + // set MUX + Device->WriteCommand( Device, 0xCA ); + WriteDataByte( Device, Device->Height - 1 ); + + // phase 1 & 2 period (needed?) + Device->WriteCommand( Device, 0xB1 ); + WriteDataByte( Device, 0xE2 ); + + // set pre-charge V (needed?°) + Device->WriteCommand( Device, 0xBB ); + WriteDataByte( Device, 0x1F ); + + // set COM deselect voltage (needed?) + Device->WriteCommand( Device, 0xBE ); + WriteDataByte( Device, 0x07 ); + + // no Display Inversion + Device->WriteCommand( Device, 0xA6 ); + + // gone with the wind + Device->DisplayOn( Device ); + Device->Update( Device ); + + return true; +} + +static const struct GDS_Device SSD1322 = { + .DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast, + .SetVFlip = SetVFlip, .SetHFlip = SetHFlip, + .Update = Update, .Init = Init, +}; + +struct GDS_Device* SSD1322_Detect(char *Driver, struct GDS_Device* Device) { + if (!strcasestr(Driver, "SSD1322")) return NULL; + + if (!Device) Device = calloc(1, sizeof(struct GDS_Device)); + + *Device = SSD1322; + Device->Depth = 4; + + return Device; +} \ No newline at end of file diff --git a/components/display/display.c b/components/display/display.c index 1da64344..82110397 100644 --- a/components/display/display.c +++ b/components/display/display.c @@ -59,8 +59,8 @@ static EXT_RAM_ATTR struct { static void displayer_task(void *args); struct GDS_Device *display; -extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SSD1675_Detect; -GDS_DetectFunc *drivers[] = { SH1106_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, NULL }; +extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SSD1675_Detect, SSD1322_Detect; +GDS_DetectFunc *drivers[] = { SH1106_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, SSD1322_Detect, NULL }; /**************************************************************************************** * diff --git a/components/squeezelite/display.c b/components/squeezelite/display.c index a7e36e4f..982c83cf 100644 --- a/components/squeezelite/display.c +++ b/components/squeezelite/display.c @@ -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; @@ -613,22 +616,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 +738,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 +758,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 +814,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 +855,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 >> 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 +897,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/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; } @@ -934,11 +937,11 @@ static void visu_update(void) { } } } 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); + draw_VU(display, vu_bitmap, visu.bars[0].current, 0, visu.row, visu.width / 2); + draw_VU(display, vu_bitmap, visu.bars[1].current, visu.width / 2, visu.row, visu.width / 2); } 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.width); } } @@ -976,12 +979,11 @@ 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; // what type of visu if (visu.mode & VISU_ESP32) { @@ -993,7 +995,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,7 +1003,8 @@ 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; // is this spectrum or analogue/digital @@ -1016,22 +1019,27 @@ 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; + visu.max = visu.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); + visu.max = visu.style ? (VU_COUNT - 1) : (visu.height - 1); } do { @@ -1039,14 +1047,14 @@ static void visu_handler( u8_t *data, int len) { 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; - + // 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; diff --git a/plugin/SqueezeESP32.zip b/plugin/SqueezeESP32.zip index 8edf88e580f84dd3167c27edd352bf3bae6cc43c..81d7585ae61dfb619cc10e3ac4583e1589bb4375 100644 GIT binary patch delta 3863 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 diff --git a/plugin/SqueezeESP32/Graphics.pm b/plugin/SqueezeESP32/Graphics.pm index 5506fdf7..43144ac3 100644 --- a/plugin/SqueezeESP32/Graphics.pm +++ b/plugin/SqueezeESP32/Graphics.pm @@ -77,7 +77,7 @@ sub displayWidth { if ($display->widthOverride) { my $artwork = $prefs->client($client)->get('artwork'); - if ($artwork->{'enable'} && $artwork->{'y'} < 32 && $client->isPlaying) { + if ($artwork->{'enable'} && $artwork->{'y'} < 32 && ($client->isPlaying || $client->isPaused)) { return $artwork->{x} + ($display->modes->[$mode || 0]{_width} || 0); } else { return $display->widthOverride + ($display->modes->[$mode || 0]{_width} || 0); @@ -168,45 +168,58 @@ sub build_modes { # mode 9 { desc => ['VISUALIZER_VUMETER'], bar => 0, secs => 0, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, 0] }, + params => [$VISUALIZER_VUMETER_ESP32, $width, 0] }, # mode 10 { desc => ['VISUALIZER_ANALOG_VUMETER'], bar => 0, secs => 0, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, 1] }, + params => [$VISUALIZER_VUMETER_ESP32, $width, 1] }, # mode 11 { desc => ['VISUALIZER_SPECTRUM_ANALYZER'], bar => 0, secs => 0, width => $width, # extra parameters (bars) - params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, + params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, ); my @extra = ( # mode E1 { desc => ['VISUALIZER_VUMETER', 'AND', 'ELAPSED'], bar => 0, secs => 1, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, 0] }, + params => [$VISUALIZER_VUMETER_ESP32, $width, 0] }, # mode E2 { desc => ['VISUALIZER_ANALOG_VUMETER', 'AND', 'ELAPSED'], bar => 0, secs => 1, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, 1] }, + params => [$VISUALIZER_VUMETER_ESP32, $width, 1] }, # mode E3 { desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'ELAPSED'], bar => 0, secs => 1, width => $width, # extra parameters (bars) - params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, + params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, # mode E4 { desc => ['VISUALIZER_VUMETER', 'AND', 'REMAINING'], bar => 0, secs => -1, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, 0] }, + params => [$VISUALIZER_VUMETER_ESP32, $width, 0] }, # mode E5 { desc => ['VISUALIZER_ANALOG_VUMETER', 'AND', 'REMAINING'], bar => 0, secs => -1, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, 1] }, + params => [$VISUALIZER_VUMETER_ESP32, $width, 1] }, # mode E6 { desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'REMAINING'], bar => 0, secs => -1, width => $width, # extra parameters (bars) - params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, + params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, + # mode E7 + { desc => ['VISUALIZER_VUMETER', 'AND', 'PROGRESS_BAR', 'AND', 'REMAINING'], + bar => 1, secs => -1, width => $width, + params => [$VISUALIZER_VUMETER_ESP32, $width, 0] }, + # mode E8 + { desc => ['VISUALIZER_ANALOG_VUMETER', 'AND', 'PROGRESS_BAR', 'AND', 'REMAINING'], + bar => 1, secs => -1, width => $width, + params => [$VISUALIZER_VUMETER_ESP32, $width, 1] }, + # mode E9 + { desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'PROGRESS_BAR', 'AND', 'REMAINING'], + bar => 1, secs => -1, width => $width, + # extra parameters (bars) + params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, ); @modes = (@modes, @extra) if $cprefs->get('height') > 32; diff --git a/plugin/SqueezeESP32/Plugin.pm b/plugin/SqueezeESP32/Plugin.pm index 36627ad0..dd9aee47 100644 --- a/plugin/SqueezeESP32/Plugin.pm +++ b/plugin/SqueezeESP32/Plugin.pm @@ -35,8 +35,22 @@ sub initPlugin { Slim::Control::Request::subscribe( sub { onNotification(@_) }, [ ['newmetadata'] ] ); Slim::Control::Request::subscribe( sub { onNotification(@_) }, [ ['playlist'], ['open', 'newsong'] ]); + Slim::Control::Request::subscribe( \&onStopClear, [ ['playlist'], ['stop', 'clear'] ]); } +sub onStopClear { + my $request = shift; + my $client = $request->client; + my $artwork = $prefs->client($client)->get('artwork'); + + if ($client->model eq 'squeezeesp32' && $artwork->{'enable'}) { + my $reqstr = $request->getRequestString(); + $log->info("artwork stop/clear $reqstr"); + $client->pluginData('artwork_md5', '') + } +} + + sub onNotification { my $request = shift; my $client = $request->client; @@ -56,8 +70,7 @@ sub update_artwork { return unless $client->model eq 'squeezeesp32' && $artwork->{'enable'}; - my $s = $artwork->{'y'} >= 32 ? $cprefs->get('height') - $artwork->{'y'} : 32; - $s = min($s, $cprefs->get('width') - $artwork->{'x'}); + my $s = min($cprefs->get('height') - $artwork->{'y'}, $cprefs->get('width') - $artwork->{'x'}); my $path = 'music/current/cover_' . $s . 'x' . $s . '_o.jpg'; my $body = Slim::Web::Graphics::artworkRequest($client, $path, $params, \&send_artwork, undef, HTTP::Response->new); diff --git a/plugin/SqueezeESP32/install.xml b/plugin/SqueezeESP32/install.xml index fd652e0f..9d5f45b6 100644 --- a/plugin/SqueezeESP32/install.xml +++ b/plugin/SqueezeESP32/install.xml @@ -10,6 +10,6 @@ PLUGIN_SQUEEZEESP32 PLUGIN_SQUEEZEESP32_DESC Plugins::SqueezeESP32::Plugin - 0.61 + 0.70 Philippe diff --git a/plugin/repo.xml b/plugin/repo.xml index 23c2d1b0..677847de 100644 --- a/plugin/repo.xml +++ b/plugin/repo.xml @@ -1,10 +1,10 @@ - + https://github.com/sle118/squeezelite-esp32 Philippe - 5c45fed832e6f79f709bef5f2da511071d1c776e + 2a8cb954928e0cd8f521acd94b90ce9f34a7a1f0 philippe_44@outlook.com SqueezeESP32 additional player id (100) http://github.com/sle118/squeezelite-esp32/raw/master/plugin/SqueezeESP32.zip From c994c5f3e3e7047efe2e4ec6a4350473315ee8e8 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Thu, 2 Apr 2020 17:07:54 -0700 Subject: [PATCH 2/5] tweak for square displays & vertical VU - release --- components/squeezelite/display.c | 103 +++++++++++++++++++++---------- plugin/SqueezeESP32.zip | Bin 8316 -> 8346 bytes plugin/SqueezeESP32/Graphics.pm | 33 +++++----- plugin/SqueezeESP32/install.xml | 2 +- plugin/repo.xml | 2 +- 5 files changed, 89 insertions(+), 51 deletions(-) diff --git a/components/squeezelite/display.c b/components/squeezelite/display.c index 982c83cf..0e2ab177 100644 --- a/components/squeezelite/display.c +++ b/components/squeezelite/display.c @@ -183,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; @@ -580,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; @@ -596,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_DrawPixelFast(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_DrawPixelFast(display, c + x, r + y, *data++ >> scale); + } } + } else { + for (int r = 0; r < width; r++) { + for (int c = 0; c < VU_HEIGHT; c++) { + GDS_DrawPixelFast(display, r + x, c + y, *data++ >> scale); + } + } } // need to manually set dirty flag as DrawPixel does not do it @@ -921,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, visu.width / 2); - draw_VU(display, vu_bitmap, visu.bars[1].current, visu.width / 2, visu.row, visu.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, visu.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; @@ -960,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 */ @@ -984,6 +1030,7 @@ static void visu_handler( u8_t *data, int len) { if (visu.mode) { // these will be overidden if necessary visu.col = visu.border = 0; + visu.rotate = false; // what type of visu if (visu.mode & VISU_ESP32) { @@ -1007,6 +1054,9 @@ static void visu_handler( u8_t *data, int len) { 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); @@ -1031,22 +1081,9 @@ static void visu_handler( u8_t *data, int len) { 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 = visu.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) : (visu.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) { diff --git a/plugin/SqueezeESP32.zip b/plugin/SqueezeESP32.zip index 81d7585ae61dfb619cc10e3ac4583e1589bb4375..a0fe0991552e8c9674071fccd73834981c07386f 100644 GIT binary patch delta 2522 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 delta 2478 zcmV;f2~qZ%LHs~}P)h>@6aWAK2ml71fl$jPu>X_?004m<000XB002jFVQ^?^V{R>#*cAvqvpNMi0HAoAVay}TfRLhGnb z2gvO&`~2#TYVZJK@lF`Qc&rYslDl*6g$C#xG`rfpr#mES8A#4W?v;#IkeQWD2Z;0^m3~u;@fX6`J zEMTt5cv1DGgJm9RXWXyXRMby+#~T759>0ey*b0@{w7g0_Ijn`@t2-qVyd`@DKLV-n5jCbW6xroqF1(qgUMb>!r!c7$QIXJgZBc|d6clA*TVe!{kD*$7pyM?k8;*lzkV^-0#b>4n z!ZEHWbA_9R!$?>oA^wYR!6j74?eB>YTfnvG_d&T{heZM&gou^k6!0LC%CCijo@z&Q zU7){zBn^?*S-wds%R(wLP(QRCt0x7d?K+&h&I~wXV-CWDu^|KtVBiJ7&44kN8{hDn zJPCcv5R5<;Gi{3@$Q5Nc^8}D0#LVEE;e-rq4&;U}jK0Hk;2u!JKJ~nD44B|p7-dHL z4F7nn#`MO1;Eiq0@G{{F#h?zOc~Yw0t4y(fEA=Q3RJeeNFmTf-C9fW%qA`|M5-du@ zJVkzbB3BTIxKP9_%%iB5Mo_$QeJ+VtI+lQVi_XygtLFM^LZPdX_?)x8nl;_yNnS1`@#1BHz+}$<$33 za65}AW;!NCrjT@1KF@nH%!Ry?t}cK%oUN$bl9S6QR|=VdRR6D)L^`NOO46Wz{lFfM zgo`ur)bN*jyLj*5ppH|xTG8R4Lf`mNtDx<*;nAN7#@j4-<~iZmUD9zkn;+NV1T2p_ zPmFB$3$#wVfE=}ur~&q*YdJVsaIX0*aAwJ9jd}_M%BhgPJ;iX#a3WBh9F8OsK)c6; z0a8Uy))ZP2B*CF2F~|$HrnGQDxmG+E{h*=kUH|j3QZQx*@BWdu+r>PbwOHomo>k&<)F8Zr?ea#d?0==mOHb`De8r{e%hw39$FRg1pKyB72VcYy`m zN}zYB`!pTmBM>BKuDvyXkb=e0YT&_xR+Kx?0r+nHUCE{cLdE_&m6EkbooV9l6{AH)v z?e?BFIx9x2zc#v$&05Z8v(;#Ko6on!SiPdT`et+VK+-s)ubqN_u3k0McXMuZnx~DE zvy-!z+u|-&^()1F0FX2JtabkE7gSo0&vZQVi;R9R%lDKu)7|Eqi*~R3>ipf)ix)4N zofj9a))}UJFJjYSlJ@BRJ-VNBXT!5{_q5S!?d47{T`8^15ga`6P7u4mrXnyvI?DuZ zd{B%uq}!_LIZ%9m1QnbFg8-j@Rd(*g)W5HB6?hreW(_03Eja z2pgqSlF(^qHIol=ncV(D;Sc3Bnd^T&vpQTyr@1a4@bY=y;YErLnBvDaiJ=Ix&5f3Z1qRx_x$BwajTkh ztGWm6_jGI%i-~xbVqBy(I)+3Sca}*o2$%SwZ6k;r-|_3rC(^mqBTBRSd(Nc0>!01; zcVkhrrohfL`n#T1bDq}sA=Xu0{ZFZuCgbid((bu-hXh+p%EtZu=(Y4%@cZOcf1jNFN||TfgG;dP-$sxpln!Yt1@U+yCp zHm#D;9<38bujBJ%5l7B*U2$nNuH$cX@rItB0Ja`=2f3i42r7K%jr7cOj}$e3lUM=y z>kb?$E+nl#gcNm+#d3LV8ZV9cOiH7G^zlG{dTw{J%}!{SrtGUh{K5WBnhrLQftse@kIO8Q)dEPT4&_P^ zi`*Ma^YMRyj81nl^6zH9vvv#=4-N*Mfl$jPu>X_?004mHz=%3jibl00000001BW0012e003!jb97;BY%X|hYzhD%000000096P0PLT{WSR(* sqaHi~Sd-u$S_0(`lRO_`0lJf(A6fyvlldQ90jrZ%AU+0Q8vpclient; my $cprefs = $prefs->client($client); - my $width = $cprefs->get('width') || 128; my $artwork = $cprefs->get('artwork'); - + my $disp_width = $cprefs->get('width') || 128; + # if artwork is in main display, reduce width - $width = $artwork->{'x'} if $artwork->{'enable'} && $artwork->{y} < 32; - + my $width = ($artwork->{'enable'} && $artwork->{'y'} < 32) ? $artwork->{'x'} : $disp_width; + my $width_low = ($artwork->{'enable'} && ($artwork->{'y'} >= 32 || $disp_width - $artwork->{'x'} > 32)) ? $artwork->{'x'} : $disp_width; + my $small_VU = $cprefs->get('small_VU'); my $spectrum = $cprefs->get('spectrum'); @@ -168,58 +169,58 @@ sub build_modes { # mode 9 { desc => ['VISUALIZER_VUMETER'], bar => 0, secs => 0, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, $width, 0] }, + params => [$VISUALIZER_VUMETER_ESP32, $width_low, 0] }, # mode 10 { desc => ['VISUALIZER_ANALOG_VUMETER'], bar => 0, secs => 0, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, $width, 1] }, + params => [$VISUALIZER_VUMETER_ESP32, $width_low, 1] }, # mode 11 { desc => ['VISUALIZER_SPECTRUM_ANALYZER'], bar => 0, secs => 0, width => $width, # extra parameters (bars) - params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, + params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width_low, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, ); my @extra = ( # mode E1 { desc => ['VISUALIZER_VUMETER', 'AND', 'ELAPSED'], bar => 0, secs => 1, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, $width, 0] }, + params => [$VISUALIZER_VUMETER_ESP32, $width_low, 0] }, # mode E2 { desc => ['VISUALIZER_ANALOG_VUMETER', 'AND', 'ELAPSED'], bar => 0, secs => 1, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, $width, 1] }, + params => [$VISUALIZER_VUMETER_ESP32, $width_low, 1] }, # mode E3 { desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'ELAPSED'], bar => 0, secs => 1, width => $width, # extra parameters (bars) - params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, + params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width_low, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, # mode E4 { desc => ['VISUALIZER_VUMETER', 'AND', 'REMAINING'], bar => 0, secs => -1, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, $width, 0] }, + params => [$VISUALIZER_VUMETER_ESP32, $width_low, 0] }, # mode E5 { desc => ['VISUALIZER_ANALOG_VUMETER', 'AND', 'REMAINING'], bar => 0, secs => -1, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, $width, 1] }, + params => [$VISUALIZER_VUMETER_ESP32, $width_low, 1] }, # mode E6 { desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'REMAINING'], bar => 0, secs => -1, width => $width, # extra parameters (bars) - params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, + params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width_low, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, # mode E7 { desc => ['VISUALIZER_VUMETER', 'AND', 'PROGRESS_BAR', 'AND', 'REMAINING'], bar => 1, secs => -1, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, $width, 0] }, + params => [$VISUALIZER_VUMETER_ESP32, $width_low, 0] }, # mode E8 { desc => ['VISUALIZER_ANALOG_VUMETER', 'AND', 'PROGRESS_BAR', 'AND', 'REMAINING'], bar => 1, secs => -1, width => $width, - params => [$VISUALIZER_VUMETER_ESP32, $width, 1] }, + params => [$VISUALIZER_VUMETER_ESP32, $width_low, 1] }, # mode E9 { desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'PROGRESS_BAR', 'AND', 'REMAINING'], bar => 1, secs => -1, width => $width, # extra parameters (bars) - params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, + params => [$VISUALIZER_SPECTRUM_ANALYZER_ESP32, $width_low, int ($width/$spectrum->{full}->{band}), $spectrum->{scale}] }, ); @modes = (@modes, @extra) if $cprefs->get('height') > 32; diff --git a/plugin/SqueezeESP32/install.xml b/plugin/SqueezeESP32/install.xml index 9d5f45b6..cab27f46 100644 --- a/plugin/SqueezeESP32/install.xml +++ b/plugin/SqueezeESP32/install.xml @@ -10,6 +10,6 @@ PLUGIN_SQUEEZEESP32 PLUGIN_SQUEEZEESP32_DESC Plugins::SqueezeESP32::Plugin - 0.70 + 0.71 Philippe diff --git a/plugin/repo.xml b/plugin/repo.xml index 677847de..45cb9296 100644 --- a/plugin/repo.xml +++ b/plugin/repo.xml @@ -1,7 +1,7 @@ - + https://github.com/sle118/squeezelite-esp32 Philippe 2a8cb954928e0cd8f521acd94b90ce9f34a7a1f0 From 402da30bea2140eade8fce4b0ce0981c347f9626 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Thu, 2 Apr 2020 17:22:42 -0700 Subject: [PATCH 3/5] forgot SHA1 --- plugin/SqueezeESP32.zip | Bin 8346 -> 8345 bytes plugin/SqueezeESP32/install.xml | 2 +- plugin/repo.xml | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin/SqueezeESP32.zip b/plugin/SqueezeESP32.zip index a0fe0991552e8c9674071fccd73834981c07386f..329291cefd2700337eaea8539cc898fc5c95209c 100644 GIT binary patch delta 360 zcmV-u0hj)oL773YL<_+v^z2qbBK4{q?4=slqJJIbZH07dEYu(H^Z6Mz7=ZWD!Tsb6s(1G_K=sbn%9s zo&dHUbqBeiq6jK{=Z*BtbB`1?f0I}N`RfiGDlR0gKZF!@jm2_#Z5l6)`AkZqfb{V| ze|m0r=x^#;ijw=#skcL*gnk(Yq^sl#$U)BpZztz0d2+}=Mt73_JNWv^Mr^2-Y#T{7+ON-OH_(J{2R%h)ZDk(x^@Q#CRam(5OSm!|Bi zLHxn~O_~likb#<}-;c{Il2sU?Q-^Y;5Jm2drTO^3Kt`uK8Tog!U$b@$?hy&Cih@wH zNjSwA$+Zs7BhE}p^w&FiH5R%&=X`S?b79>m8ST+JVe~4VC$l(mp6ilJqj44gpo`b^ z{0y-1s9VSd6-7|u2d|}Po_nOI`Mbmt$bYxzP;nt?^(myND$Ey)8&i8}%vVwv1*D66 zf6{ZiLw{RUQWV^WPMsYBCG=}QAYCTcKn{8$cr!W|As^I~i;^-a6hj*}1rlV}k(_P` znk%H6r|rYzbIxA2S@xD?Y;$!9q)o>CU13GlK01Zw_ZhnbGEh@#Wy)HH;<_bb4DJyLqKJY} zphxL?6O(KnFa?(b7KTfcp&mT}c9Y*8S^)!-Iv-*I*prPLUGIN_SQUEEZEESP32 PLUGIN_SQUEEZEESP32_DESC Plugins::SqueezeESP32::Plugin - 0.71 + 0.72 Philippe diff --git a/plugin/repo.xml b/plugin/repo.xml index 45cb9296..ffb006d5 100644 --- a/plugin/repo.xml +++ b/plugin/repo.xml @@ -1,10 +1,10 @@ - + https://github.com/sle118/squeezelite-esp32 Philippe - 2a8cb954928e0cd8f521acd94b90ce9f34a7a1f0 + 50679aff5e938359342d3a4d8251dcd25fab3eff philippe_44@outlook.com SqueezeESP32 additional player id (100) http://github.com/sle118/squeezelite-esp32/raw/master/plugin/SqueezeESP32.zip From a094b0d61fde7d3858198463a53324ff4473d61b Mon Sep 17 00:00:00 2001 From: Philippe G Date: Fri, 3 Apr 2020 18:40:45 -0700 Subject: [PATCH 4/5] visu with fixed output - release --- components/squeezelite/decode_external.c | 2 +- components/squeezelite/display.c | 4 ++-- components/squeezelite/embedded.h | 4 ++-- components/squeezelite/output_bt.c | 2 +- components/squeezelite/output_i2s.c | 2 +- components/squeezelite/output_visu.c | 3 ++- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/components/squeezelite/decode_external.c b/components/squeezelite/decode_external.c index 7b0f73b5..0f298d46 100644 --- a/components/squeezelite/decode_external.c +++ b/components/squeezelite/decode_external.c @@ -207,7 +207,7 @@ static bool raop_sink_cmd_handler(raop_event_t event, va_list args) // first must make sure we started on time if (raop_sync.win == SYNC_WIN_START) { // how many ms have we really played - ms = now - output.updated + ((u64_t) (output.frames_played_dmp - output.device_frames) * 1000) / RAOP_SAMPLE_RATE; + ms = now - output.updated + ((output.frames_played_dmp - output.device_frames) * 10) / (RAOP_SAMPLE_RATE / 100); error = ms - (now - raop_sync.start_time); LOG_INFO("backend played %u, desired %u, (delta:%d)", ms, now - raop_sync.start_time, ms - (now - raop_sync.start_time)); diff --git a/components/squeezelite/display.c b/components/squeezelite/display.c index 0e2ab177..49ba7534 100644 --- a/components/squeezelite/display.c +++ b/components/squeezelite/display.c @@ -864,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 = visu.max * (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; } @@ -906,7 +906,7 @@ static void visu_update(void) { } // convert to dB and bars, same back-off - if (power) visu.bars[i].current = visu.max * (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; } diff --git a/components/squeezelite/embedded.h b/components/squeezelite/embedded.h index 14769aef..d599f565 100644 --- a/components/squeezelite/embedded.h +++ b/components/squeezelite/embedded.h @@ -62,11 +62,11 @@ void decode_restore(int external); // to be defined to nothing if you don't want to support these extern struct visu_export_s { pthread_mutex_t mutex; - u32_t level, size, rate; + u32_t level, size, rate, gain; s16_t *buffer; bool running; } visu_export; -void output_visu_export(s16_t *frames, frames_t out_frames, u32_t rate, bool silence); +void output_visu_export(s16_t *frames, frames_t out_frames, u32_t rate, bool silence, u32_t gain); void output_visu_init(log_level level); void output_visu_close(void); diff --git a/components/squeezelite/output_bt.c b/components/squeezelite/output_bt.c index e4c5ba1a..72cf6d39 100644 --- a/components/squeezelite/output_bt.c +++ b/components/squeezelite/output_bt.c @@ -121,7 +121,7 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g memcpy(btout + oframes * BYTES_PER_FRAME, buf, out_frames * BYTES_PER_FRAME); } - output_visu_export((s16_t*) (btout + oframes * BYTES_PER_FRAME), out_frames, output.current_sample_rate, silence); + output_visu_export((s16_t*) (btout + oframes * BYTES_PER_FRAME), out_frames, output.current_sample_rate, silence, (gainL + gainR) / 2); return (int)out_frames; } diff --git a/components/squeezelite/output_i2s.c b/components/squeezelite/output_i2s.c index 4336fd99..a56ee7fe 100644 --- a/components/squeezelite/output_i2s.c +++ b/components/squeezelite/output_i2s.c @@ -367,7 +367,7 @@ static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32 _scale_and_pack_frames(obuf + oframes * bytes_per_frame, optr, out_frames, gainL, gainR, output.format); #endif - output_visu_export((s16_t*) (obuf + oframes * bytes_per_frame), out_frames, output.current_sample_rate, silence); + output_visu_export((s16_t*) (obuf + oframes * bytes_per_frame), out_frames, output.current_sample_rate, silence, (gainL + gainR) / 2); oframes += out_frames; diff --git a/components/squeezelite/output_visu.c b/components/squeezelite/output_visu.c index 20a9da0a..2a847a2b 100644 --- a/components/squeezelite/output_visu.c +++ b/components/squeezelite/output_visu.c @@ -29,7 +29,7 @@ static struct visu_export_s *visu = &visu_export; static log_level loglevel = lINFO; -void output_visu_export(s16_t *frames, frames_t out_frames, u32_t rate, bool silence) { +void output_visu_export(s16_t *frames, frames_t out_frames, u32_t rate, bool silence, u32_t gain) { // no data to process if (silence) { @@ -50,6 +50,7 @@ void output_visu_export(s16_t *frames, frames_t out_frames, u32_t rate, bool sil visu->level += space / 2; visu->running = true; visu->rate = rate ? rate : 44100; + visu->gain = gain; } // mutex must be released From 1ab183335efb00b9892faf2cac07e300a98fbd95 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Sat, 4 Apr 2020 13:28:57 -0700 Subject: [PATCH 5/5] more airplay saga - release --- components/raop/rtp.c | 4 ++-- components/squeezelite/decode_external.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/raop/rtp.c b/components/raop/rtp.c index 58c6e7c8..a659c1eb 100644 --- a/components/raop/rtp.c +++ b/components/raop/rtp.c @@ -434,7 +434,7 @@ static void buffer_put_packet(rtp_t *ctx, seq_t seqno, unsigned rtptime, bool fi ctx->flush_seqno = -1; ctx->playing = true; ctx->resent_req = ctx->resent_rec = ctx->silent_frames = ctx->discarded = 0; - playtime = ctx->synchro.time + (((s32_t)(rtptime - ctx->synchro.rtp)) * 1000) / RAOP_SAMPLE_RATE; + playtime = ctx->synchro.time + ((rtptime - ctx->synchro.rtp) * 10) / (RAOP_SAMPLE_RATE / 100); ctx->cmd_cb(RAOP_PLAY, playtime); } else { pthread_mutex_unlock(&ctx->ab_mutex); @@ -517,7 +517,7 @@ static void buffer_push_packet(rtp_t *ctx) { // try to manage playtime so that we overflow as late as possible if we miss NTP (2^31 / 10 / 44100) curframe = ctx->audio_buffer + BUFIDX(ctx->ab_read); - playtime = ctx->synchro.time + (((s32_t)(curframe->rtptime - ctx->synchro.rtp)) * 10) / (RAOP_SAMPLE_RATE / 100); + playtime = ctx->synchro.time + ((curframe->rtptime - ctx->synchro.rtp) * 10) / (RAOP_SAMPLE_RATE / 100); if (now > playtime) { LOG_DEBUG("[%p]: discarded frame now:%u missed by:%d (W:%hu R:%hu)", ctx, now, now - playtime, ctx->ab_write, ctx->ab_read); diff --git a/components/squeezelite/decode_external.c b/components/squeezelite/decode_external.c index 0f298d46..e51789bc 100644 --- a/components/squeezelite/decode_external.c +++ b/components/squeezelite/decode_external.c @@ -210,7 +210,7 @@ static bool raop_sink_cmd_handler(raop_event_t event, va_list args) ms = now - output.updated + ((output.frames_played_dmp - output.device_frames) * 10) / (RAOP_SAMPLE_RATE / 100); error = ms - (now - raop_sync.start_time); - LOG_INFO("backend played %u, desired %u, (delta:%d)", ms, now - raop_sync.start_time, ms - (now - raop_sync.start_time)); + LOG_INFO("backend played %u, desired %u, (delta:%d)", ms, now - raop_sync.start_time, error); } else { u32_t level = _buf_used(outputbuf);