mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-07 20:17:04 +03:00
add SSD1322 + few tweaks - release
This commit is contained in:
203
components/display/SSD1322.c
Normal file
203
components/display/SSD1322.c
Normal file
@@ -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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <esp_heap_caps.h>
|
||||||
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
@@ -59,8 +59,8 @@ static EXT_RAM_ATTR struct {
|
|||||||
static void displayer_task(void *args);
|
static void displayer_task(void *args);
|
||||||
|
|
||||||
struct GDS_Device *display;
|
struct GDS_Device *display;
|
||||||
extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SSD1675_Detect;
|
extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SSD1675_Detect, SSD1322_Detect;
|
||||||
GDS_DetectFunc *drivers[] = { SH1106_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, NULL };
|
GDS_DetectFunc *drivers[] = { SH1106_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, SSD1322_Detect, NULL };
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -73,12 +73,15 @@ struct visu_packet {
|
|||||||
u8_t which;
|
u8_t which;
|
||||||
u8_t count;
|
u8_t count;
|
||||||
union {
|
union {
|
||||||
union {
|
struct {
|
||||||
struct {
|
u32_t width;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
u32_t bars;
|
u32_t bars;
|
||||||
u32_t spectrum_scale;
|
u32_t spectrum_scale;
|
||||||
};
|
};
|
||||||
u32_t style;
|
u32_t style;
|
||||||
|
};
|
||||||
} full;
|
} full;
|
||||||
struct {
|
struct {
|
||||||
u32_t width;
|
u32_t width;
|
||||||
@@ -613,22 +616,22 @@ static void grfe_handler( u8_t *data, int len) {
|
|||||||
scroller.active = false;
|
scroller.active = false;
|
||||||
|
|
||||||
// visu has priority when full screen on small screens
|
// 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);
|
xSemaphoreGive(displayer.mutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// are we in control
|
// are we in control
|
||||||
if (displayer.owned) {
|
if (displayer.owned) {
|
||||||
// did we have something that might have write on the bottom of a SB_HEIGHT+ display
|
// draw new frame, it might be less than full screen (small visu)
|
||||||
if (displayer.dirty) {
|
int width = ((len - sizeof(struct grfe_packet)) * 8) / displayer.height;
|
||||||
GDS_ClearExt(display, true);
|
|
||||||
|
// 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;
|
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
|
// when doing screensaver, that frame becomes a visu background
|
||||||
if (!(visu.mode & VISU_ESP32)) {
|
if (!(visu.mode & VISU_ESP32)) {
|
||||||
visu.back.width = width;
|
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);
|
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
|
// 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);
|
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
|
// 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
|
// if we just got a content update, let the scroller manage the screen
|
||||||
LOG_DEBUG("resuming scrolling task");
|
LOG_DEBUG("resuming scrolling task");
|
||||||
@@ -811,7 +814,7 @@ static void grfa_handler(u8_t *data, int len) {
|
|||||||
artwork.size += size;
|
artwork.size += size;
|
||||||
if (artwork.size == length) {
|
if (artwork.size == length) {
|
||||||
GDS_ClearWindow(display, artwork.x, artwork.y, -1, -1, GDS_COLOR_BLACK);
|
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);
|
free(artwork.data);
|
||||||
artwork.data = NULL;
|
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)
|
// 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;) {
|
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;
|
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;
|
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
|
// 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;
|
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;
|
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) {
|
} 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[0].current, 0, visu.row, visu.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[1].current, visu.width / 2, visu.row, visu.width / 2);
|
||||||
} else {
|
} else {
|
||||||
int level = (visu.bars[0].current + visu.bars[1].current) / 2;
|
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;
|
visu.mode = pkt->which;
|
||||||
|
|
||||||
// little trick to clean the taller screens when switching visu
|
// 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) {
|
if (visu.mode) {
|
||||||
// these will be overidden if necessary
|
// these will be overidden if necessary
|
||||||
visu.col = visu.border = 0;
|
visu.col = visu.border = 0;
|
||||||
visu.width = displayer.width;
|
|
||||||
|
|
||||||
// what type of visu
|
// what type of visu
|
||||||
if (visu.mode & VISU_ESP32) {
|
if (visu.mode & VISU_ESP32) {
|
||||||
@@ -993,7 +995,7 @@ static void visu_handler( u8_t *data, int len) {
|
|||||||
|
|
||||||
visu.style = 0;
|
visu.style = 0;
|
||||||
visu.width = htonl(pkt->width);
|
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.col = pkt->col < 0 ? displayer.width + pkt->col : pkt->col;
|
||||||
visu.row = pkt->row < 0 ? GDS_GetHeight(display) + pkt->row : pkt->row;
|
visu.row = pkt->row < 0 ? GDS_GetHeight(display) + pkt->row : pkt->row;
|
||||||
visu.border = htonl(pkt->border);
|
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.;
|
visu.spectrum_scale = htonl(pkt->spectrum_scale) / 100.;
|
||||||
} else {
|
} else {
|
||||||
// full screen visu, try to use bottom screen if available
|
// 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;
|
visu.row = GDS_GetHeight(display) - visu.height;
|
||||||
|
|
||||||
// is this spectrum or analogue/digital
|
// is this spectrum or analogue/digital
|
||||||
@@ -1016,22 +1019,27 @@ static void visu_handler( u8_t *data, int len) {
|
|||||||
} else {
|
} else {
|
||||||
// classical (screensaver) mode, don't try to optimize screen usage & force some params
|
// classical (screensaver) mode, don't try to optimize screen usage & force some params
|
||||||
visu.row = 0;
|
visu.row = 0;
|
||||||
visu.height = SB_HEIGHT;
|
visu.height = GDS_GetHeight(display);
|
||||||
|
visu.width = displayer.width;
|
||||||
visu.spectrum_scale = 0.25;
|
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));
|
if (visu.mode == VISU_SPECTRUM) {
|
||||||
else visu.style = htonl(pkt->classical_vu.style);
|
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;
|
if (bars > MAX_BARS) bars = MAX_BARS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to adapt to what we have
|
// try to adapt to what we have
|
||||||
if ((visu.mode & ~VISU_ESP32) == VISU_SPECTRUM) {
|
if ((visu.mode & ~VISU_ESP32) == VISU_SPECTRUM) {
|
||||||
visu.n = bars ? bars : MAX_BARS;
|
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;
|
if (visu.spectrum_scale <= 0 || visu.spectrum_scale > 0.5) visu.spectrum_scale = 0.5;
|
||||||
spectrum_limits(0, visu.n, 0);
|
spectrum_limits(0, visu.n, 0);
|
||||||
} else {
|
} else {
|
||||||
visu.n = 2;
|
visu.n = 2;
|
||||||
visu.max = visu.style ? (VU_COUNT - 1) : (displayer.height - 1);
|
visu.max = visu.style ? (VU_COUNT - 1) : (visu.height - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -1039,14 +1047,14 @@ static void visu_handler( u8_t *data, int len) {
|
|||||||
if (visu.bar_width > 0) break;
|
if (visu.bar_width > 0) break;
|
||||||
} while (--visu.n);
|
} while (--visu.n);
|
||||||
visu.bar_border = (visu.width - visu.border - (visu.bar_width + visu.bar_gap) * visu.n + visu.bar_gap) / 2;
|
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
|
// give up if not enough space
|
||||||
if (visu.bar_width < 0) {
|
if (visu.bar_width < 0) {
|
||||||
visu.mode = VISU_BLANK;
|
visu.mode = VISU_BLANK;
|
||||||
LOG_WARN("Not enough room for displaying visu");
|
LOG_WARN("Not enough room for displaying visu");
|
||||||
} else {
|
} else {
|
||||||
// de-activate scroller if we are taking main screen
|
// 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);
|
vTaskResume(displayer.task);
|
||||||
}
|
}
|
||||||
visu.wake = 0;
|
visu.wake = 0;
|
||||||
|
|||||||
Binary file not shown.
@@ -77,7 +77,7 @@ sub displayWidth {
|
|||||||
|
|
||||||
if ($display->widthOverride) {
|
if ($display->widthOverride) {
|
||||||
my $artwork = $prefs->client($client)->get('artwork');
|
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);
|
return $artwork->{x} + ($display->modes->[$mode || 0]{_width} || 0);
|
||||||
} else {
|
} else {
|
||||||
return $display->widthOverride + ($display->modes->[$mode || 0]{_width} || 0);
|
return $display->widthOverride + ($display->modes->[$mode || 0]{_width} || 0);
|
||||||
@@ -168,45 +168,58 @@ sub build_modes {
|
|||||||
# mode 9
|
# mode 9
|
||||||
{ desc => ['VISUALIZER_VUMETER'],
|
{ desc => ['VISUALIZER_VUMETER'],
|
||||||
bar => 0, secs => 0, width => $width,
|
bar => 0, secs => 0, width => $width,
|
||||||
params => [$VISUALIZER_VUMETER_ESP32, 0] },
|
params => [$VISUALIZER_VUMETER_ESP32, $width, 0] },
|
||||||
# mode 10
|
# mode 10
|
||||||
{ desc => ['VISUALIZER_ANALOG_VUMETER'],
|
{ desc => ['VISUALIZER_ANALOG_VUMETER'],
|
||||||
bar => 0, secs => 0, width => $width,
|
bar => 0, secs => 0, width => $width,
|
||||||
params => [$VISUALIZER_VUMETER_ESP32, 1] },
|
params => [$VISUALIZER_VUMETER_ESP32, $width, 1] },
|
||||||
# mode 11
|
# mode 11
|
||||||
{ desc => ['VISUALIZER_SPECTRUM_ANALYZER'],
|
{ desc => ['VISUALIZER_SPECTRUM_ANALYZER'],
|
||||||
bar => 0, secs => 0, width => $width,
|
bar => 0, secs => 0, width => $width,
|
||||||
# extra parameters (bars)
|
# 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 = (
|
my @extra = (
|
||||||
# mode E1
|
# mode E1
|
||||||
{ desc => ['VISUALIZER_VUMETER', 'AND', 'ELAPSED'],
|
{ desc => ['VISUALIZER_VUMETER', 'AND', 'ELAPSED'],
|
||||||
bar => 0, secs => 1, width => $width,
|
bar => 0, secs => 1, width => $width,
|
||||||
params => [$VISUALIZER_VUMETER_ESP32, 0] },
|
params => [$VISUALIZER_VUMETER_ESP32, $width, 0] },
|
||||||
# mode E2
|
# mode E2
|
||||||
{ desc => ['VISUALIZER_ANALOG_VUMETER', 'AND', 'ELAPSED'],
|
{ desc => ['VISUALIZER_ANALOG_VUMETER', 'AND', 'ELAPSED'],
|
||||||
bar => 0, secs => 1, width => $width,
|
bar => 0, secs => 1, width => $width,
|
||||||
params => [$VISUALIZER_VUMETER_ESP32, 1] },
|
params => [$VISUALIZER_VUMETER_ESP32, $width, 1] },
|
||||||
# mode E3
|
# mode E3
|
||||||
{ desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'ELAPSED'],
|
{ desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'ELAPSED'],
|
||||||
bar => 0, secs => 1, width => $width,
|
bar => 0, secs => 1, width => $width,
|
||||||
# extra parameters (bars)
|
# 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
|
# mode E4
|
||||||
{ desc => ['VISUALIZER_VUMETER', 'AND', 'REMAINING'],
|
{ desc => ['VISUALIZER_VUMETER', 'AND', 'REMAINING'],
|
||||||
bar => 0, secs => -1, width => $width,
|
bar => 0, secs => -1, width => $width,
|
||||||
params => [$VISUALIZER_VUMETER_ESP32, 0] },
|
params => [$VISUALIZER_VUMETER_ESP32, $width, 0] },
|
||||||
# mode E5
|
# mode E5
|
||||||
{ desc => ['VISUALIZER_ANALOG_VUMETER', 'AND', 'REMAINING'],
|
{ desc => ['VISUALIZER_ANALOG_VUMETER', 'AND', 'REMAINING'],
|
||||||
bar => 0, secs => -1, width => $width,
|
bar => 0, secs => -1, width => $width,
|
||||||
params => [$VISUALIZER_VUMETER_ESP32, 1] },
|
params => [$VISUALIZER_VUMETER_ESP32, $width, 1] },
|
||||||
# mode E6
|
# mode E6
|
||||||
{ desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'REMAINING'],
|
{ desc => ['VISUALIZER_SPECTRUM_ANALYZER', 'AND', 'REMAINING'],
|
||||||
bar => 0, secs => -1, width => $width,
|
bar => 0, secs => -1, width => $width,
|
||||||
# extra parameters (bars)
|
# 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;
|
@modes = (@modes, @extra) if $cprefs->get('height') > 32;
|
||||||
|
|||||||
@@ -35,8 +35,22 @@ sub initPlugin {
|
|||||||
|
|
||||||
Slim::Control::Request::subscribe( sub { onNotification(@_) }, [ ['newmetadata'] ] );
|
Slim::Control::Request::subscribe( sub { onNotification(@_) }, [ ['newmetadata'] ] );
|
||||||
Slim::Control::Request::subscribe( sub { onNotification(@_) }, [ ['playlist'], ['open', 'newsong'] ]);
|
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 {
|
sub onNotification {
|
||||||
my $request = shift;
|
my $request = shift;
|
||||||
my $client = $request->client;
|
my $client = $request->client;
|
||||||
@@ -56,8 +70,7 @@ sub update_artwork {
|
|||||||
|
|
||||||
return unless $client->model eq 'squeezeesp32' && $artwork->{'enable'};
|
return unless $client->model eq 'squeezeesp32' && $artwork->{'enable'};
|
||||||
|
|
||||||
my $s = $artwork->{'y'} >= 32 ? $cprefs->get('height') - $artwork->{'y'} : 32;
|
my $s = min($cprefs->get('height') - $artwork->{'y'}, $cprefs->get('width') - $artwork->{'x'});
|
||||||
$s = min($s, $cprefs->get('width') - $artwork->{'x'});
|
|
||||||
|
|
||||||
my $path = 'music/current/cover_' . $s . 'x' . $s . '_o.jpg';
|
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);
|
my $body = Slim::Web::Graphics::artworkRequest($client, $path, $params, \&send_artwork, undef, HTTP::Response->new);
|
||||||
|
|||||||
@@ -10,6 +10,6 @@
|
|||||||
<name>PLUGIN_SQUEEZEESP32</name>
|
<name>PLUGIN_SQUEEZEESP32</name>
|
||||||
<description>PLUGIN_SQUEEZEESP32_DESC</description>
|
<description>PLUGIN_SQUEEZEESP32_DESC</description>
|
||||||
<module>Plugins::SqueezeESP32::Plugin</module>
|
<module>Plugins::SqueezeESP32::Plugin</module>
|
||||||
<version>0.61</version>
|
<version>0.70</version>
|
||||||
<creator>Philippe</creator>
|
<creator>Philippe</creator>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<?xml version='1.0' standalone='yes'?>
|
<?xml version='1.0' standalone='yes'?>
|
||||||
<extensions>
|
<extensions>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin version="0.61" name="SqueezeESP32" minTarget="7.5" maxTarget="*">
|
<plugin version="0.70" name="SqueezeESP32" minTarget="7.5" maxTarget="*">
|
||||||
<link>https://github.com/sle118/squeezelite-esp32</link>
|
<link>https://github.com/sle118/squeezelite-esp32</link>
|
||||||
<creator>Philippe</creator>
|
<creator>Philippe</creator>
|
||||||
<sha>5c45fed832e6f79f709bef5f2da511071d1c776e</sha>
|
<sha>2a8cb954928e0cd8f521acd94b90ce9f34a7a1f0</sha>
|
||||||
<email>philippe_44@outlook.com</email>
|
<email>philippe_44@outlook.com</email>
|
||||||
<desc lang="EN">SqueezeESP32 additional player id (100)</desc>
|
<desc lang="EN">SqueezeESP32 additional player id (100)</desc>
|
||||||
<url>http://github.com/sle118/squeezelite-esp32/raw/master/plugin/SqueezeESP32.zip</url>
|
<url>http://github.com/sle118/squeezelite-esp32/raw/master/plugin/SqueezeESP32.zip</url>
|
||||||
|
|||||||
Reference in New Issue
Block a user