mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-14 07:27:03 +03:00
Add spectrum visualizer
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
|
||||
#include "ssd13x6.h"
|
||||
|
||||
#define SHADOW_BUFFER
|
||||
|
||||
// used by both but different
|
||||
static uint8_t SSDCmd_Set_Display_Start_Line;
|
||||
static uint8_t SSDCmd_Set_Display_Offset;
|
||||
@@ -111,8 +113,32 @@ void SSD13x6_SetDisplayAddressMode( struct SSD13x6_Device* DeviceHandle, SSD13x6
|
||||
}
|
||||
|
||||
void SSD13x6_Update( struct SSD13x6_Device* DeviceHandle ) {
|
||||
#ifdef SHADOW_BUFFER
|
||||
// not sure the compiler does not have to redo all calculation in for loops, so local it is
|
||||
int width = DeviceHandle->Width, rows = DeviceHandle->Height / 8;
|
||||
uint8_t *optr = DeviceHandle->Shadowbuffer, *iptr = DeviceHandle->Framebuffer;
|
||||
|
||||
// by row, find first and last columns that have been updated
|
||||
for (int r = 0; r < rows; r++) {
|
||||
uint8_t first = 0, last;
|
||||
for (int c = 0; c < width; c++) {
|
||||
if (*iptr != *optr) {
|
||||
if (!first) first = c + 1;
|
||||
last = c ;
|
||||
}
|
||||
*optr++ = *iptr++;
|
||||
}
|
||||
|
||||
// now update the display by "byte rows"
|
||||
if (first--) {
|
||||
SSD13x6_SetColumnAddress( DeviceHandle, first, last );
|
||||
SSD13x6_SetPageAddress( DeviceHandle, r, r);
|
||||
SSD13x6_WriteData( DeviceHandle, DeviceHandle->Shadowbuffer + r*width + first, last - first + 1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (DeviceHandle->Model == SH1106) {
|
||||
// SH1106 requires a page-by-page update and ahs no end Page/Column
|
||||
// SH1106 requires a page-by-page update and has no end Page/Column
|
||||
for (int i = 0; i < DeviceHandle->Height / 8 ; i++) {
|
||||
SSD13x6_SetPageAddress( DeviceHandle, i, 0);
|
||||
SSD13x6_SetColumnAddress( DeviceHandle, 0, 0);
|
||||
@@ -124,6 +150,7 @@ void SSD13x6_Update( struct SSD13x6_Device* DeviceHandle ) {
|
||||
SSD13x6_SetPageAddress( DeviceHandle, 0, DeviceHandle->Height / 8 - 1);
|
||||
SSD13x6_WriteData( DeviceHandle, DeviceHandle->Framebuffer, DeviceHandle->FramebufferSize );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SSD13x6_WriteRawData( struct SSD13x6_Device* DeviceHandle, uint8_t* Data, size_t DataLength ) {
|
||||
@@ -214,6 +241,11 @@ static bool SSD13x6_Init( struct SSD13x6_Device* DeviceHandle, int Width, int He
|
||||
DeviceHandle->Width = Width;
|
||||
DeviceHandle->Height = Height;
|
||||
|
||||
#ifdef SHADOW_BUFFER
|
||||
DeviceHandle->Shadowbuffer = heap_caps_malloc( DeviceHandle->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
|
||||
memset( DeviceHandle->Shadowbuffer, 0xFF, DeviceHandle->FramebufferSize );
|
||||
#endif
|
||||
|
||||
SSD13x6_HWReset( DeviceHandle );
|
||||
SSD13x6_DisplayOff( DeviceHandle );
|
||||
|
||||
@@ -308,7 +340,11 @@ bool SSD13x6_Init_SPI( struct SSD13x6_Device* DeviceHandle, int Width, int Heigh
|
||||
DeviceHandle->CSPin = CSPin;
|
||||
|
||||
DeviceHandle->FramebufferSize = ( Width * Height ) / 8;
|
||||
#ifdef SHADOW_BUFFER
|
||||
DeviceHandle->Framebuffer = calloc( 1, DeviceHandle->FramebufferSize );
|
||||
#else
|
||||
DeviceHandle->Framebuffer = heap_caps_calloc( 1, DeviceHandle->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
|
||||
#endif
|
||||
NullCheck( DeviceHandle->Framebuffer, return false );
|
||||
|
||||
return SSD13x6_Init( DeviceHandle, Width, Height );
|
||||
|
||||
@@ -58,7 +58,7 @@ struct SSD13x6_Device {
|
||||
|
||||
enum { SSD1306, SSD1326, SH1106 } Model;
|
||||
uint8_t ReMap;
|
||||
uint8_t* Framebuffer;
|
||||
uint8_t* Framebuffer, *Shadowbuffer;
|
||||
int FramebufferSize;
|
||||
|
||||
WriteCommandProc WriteCommand;
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include "ssd13x6.h"
|
||||
#include "ssd13x6_draw.h"
|
||||
|
||||
#undef NullCheck
|
||||
#define NullCheck(X,Y)
|
||||
|
||||
__attribute__( ( always_inline ) ) static inline bool IsPixelVisible( struct SSD13x6_Device* DeviceHandle, int x, int y ) {
|
||||
bool Result = (
|
||||
( x >= 0 ) &&
|
||||
@@ -75,7 +78,7 @@ void IRAM_ATTR SSD13x6_DrawHLine( struct SSD13x6_Device* DeviceHandle, int x, in
|
||||
NullCheck( DeviceHandle, return );
|
||||
NullCheck( DeviceHandle->Framebuffer, return );
|
||||
|
||||
for ( ; x <= XEnd; x++ ) {
|
||||
for ( ; x < XEnd; x++ ) {
|
||||
if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
|
||||
SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color );
|
||||
} else {
|
||||
@@ -90,7 +93,7 @@ void IRAM_ATTR SSD13x6_DrawVLine( struct SSD13x6_Device* DeviceHandle, int x, in
|
||||
NullCheck( DeviceHandle, return );
|
||||
NullCheck( DeviceHandle->Framebuffer, return );
|
||||
|
||||
for ( ; y <= YEnd; y++ ) {
|
||||
for ( ; y < YEnd; y++ ) {
|
||||
if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
|
||||
SSD13x6_DrawPixel( DeviceHandle, x, y, Color );
|
||||
} else {
|
||||
@@ -114,7 +117,7 @@ static inline void IRAM_ATTR DrawWideLine( struct SSD13x6_Device* DeviceHandle,
|
||||
|
||||
Error = ( dy * 2 ) - dx;
|
||||
|
||||
for ( ; x <= x1; x++ ) {
|
||||
for ( ; x < x1; x++ ) {
|
||||
if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
|
||||
SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color );
|
||||
}
|
||||
@@ -219,3 +222,32 @@ void SSD13x6_Clear( struct SSD13x6_Device* DeviceHandle, int Color ) {
|
||||
|
||||
memset( DeviceHandle->Framebuffer, Color, DeviceHandle->FramebufferSize );
|
||||
}
|
||||
|
||||
void SSD13x6_ClearWindow( struct SSD13x6_Device* DeviceHandle, int x1, int y1, int x2, int y2, int Color ) {
|
||||
NullCheck( DeviceHandle, return );
|
||||
NullCheck( DeviceHandle->Framebuffer, return );
|
||||
|
||||
/*
|
||||
int xr = ((x1 - 1) / 8) + 1 ) * 8;
|
||||
int xl = (x2 / 8) * 8;
|
||||
|
||||
for (int y = y1; y <= y2; y++) {
|
||||
for (int x = x1; x < xr; x++) SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color);
|
||||
if (xl > xr) memset( DeviceHandle->Framebuffer + (y / 8) * DeviceHandle->Width + xr, 0, xl - xr );
|
||||
for (int x = xl; x <= x2; x++) SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color);
|
||||
}
|
||||
|
||||
return;
|
||||
*/
|
||||
|
||||
// cheap optimization on boundaries
|
||||
if (x1 == 0 && x2 == DeviceHandle->Width - 1 && y1 % 8 == 0 && (y2 + 1) % 8 == 0) {
|
||||
memset( DeviceHandle->Framebuffer + (y1 / 8) * DeviceHandle->Width, 0, (y2 - y1 + 1) / 8 * DeviceHandle->Width );
|
||||
} else {
|
||||
for (int y = y1; y <= y2; y++) {
|
||||
for (int x = x1; x <= x2; x++) {
|
||||
SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ extern "C" {
|
||||
#define SSD_COLOR_XOR 2
|
||||
|
||||
void SSD13x6_Clear( struct SSD13x6_Device* DeviceHandle, int Color );
|
||||
void SSD13x6_ClearWindow( struct SSD13x6_Device* DeviceHandle, int x1, int y1, int x2, int y2, int Color );
|
||||
void SSD13x6_DrawPixel( struct SSD13x6_Device* DeviceHandle, int X, int Y, int Color );
|
||||
void SSD13x6_DrawPixelFast( struct SSD13x6_Device* DeviceHandle, int X, int Y, int Color );
|
||||
void SSD13x6_DrawHLine( struct SSD13x6_Device* DeviceHandle, int x, int y, int Width, int Color );
|
||||
|
||||
Reference in New Issue
Block a user