"log-like" scale on spectrum visu

This commit is contained in:
philippe44
2020-02-18 18:37:03 -08:00
parent 4e7ff0a37a
commit d78c50f781
9 changed files with 83 additions and 45 deletions

View File

@@ -61,14 +61,20 @@ struct visu_packet {
u8_t which; u8_t which;
u8_t count; u8_t count;
union { union {
u32_t width; struct {
u32_t full_bars; u32_t bars;
u32_t spectrum_scale;
} full;
struct {
u32_t width;
u32_t height;
s32_t col;
s32_t row;
u32_t border;
u32_t bars;
u32_t spectrum_scale;
};
}; };
u32_t height;
s32_t col;
s32_t row;
u32_t border;
u32_t small_bars;
}; };
struct ANIC_header { struct ANIC_header {
@@ -98,8 +104,7 @@ static struct {
#define RMS_LEN_BIT 6 #define RMS_LEN_BIT 6
#define RMS_LEN (1 << RMS_LEN_BIT) #define RMS_LEN (1 << RMS_LEN_BIT)
// actually this is 2x the displayed BW #define DISPLAY_BW 20000
#define DISPLAY_BW 32000
static struct scroller_s { static struct scroller_s {
// copy of grfs content // copy of grfs content
@@ -128,9 +133,10 @@ static struct scroller_s {
static EXT_RAM_ATTR struct { static EXT_RAM_ATTR struct {
int bar_gap, bar_width, bar_border; int bar_gap, bar_width, bar_border;
struct { struct {
int current; int current, max;
int max; int limit;
} bars[MAX_BARS]; } bars[MAX_BARS];
float spectrum_scale;
int n, col, row, height, width, border; int n, col, row, height, width, border;
enum { VISU_BLANK, VISU_VUMETER, VISU_SPECTRUM, VISU_WAVEFORM } mode; enum { VISU_BLANK, VISU_VUMETER, VISU_SPECTRUM, VISU_WAVEFORM } mode;
int speed, wake; int speed, wake;
@@ -659,13 +665,14 @@ static void visu_update(void) {
// actual FFT that might be less cycle than all the crap below // actual FFT that might be less cycle than all the crap below
dsps_fft2r_fc32_ae32(visu.samples, FFT_LEN); dsps_fft2r_fc32_ae32(visu.samples, FFT_LEN);
dsps_bit_rev_fc32_ansi(visu.samples, FFT_LEN); dsps_bit_rev_fc32_ansi(visu.samples, FFT_LEN);
float rate = visu_export.rate;
// now arrange the result with the number of bar and sampling rate (don't want DC) // now arrange the result with the number of bar and sampling rate (don't want DC)
for (int i = 1, j = 1; i <= visu.n && j < (FFT_LEN / 2); i++) { for (int i = 0, j = 1; i < visu.n && j < (FFT_LEN / 2); i++) {
float power, count; float power, count;
// find the next point in FFT (this is real signal, so only half matters) // find the next point in FFT (this is real signal, so only half matters)
for (count = 0, power = 0; j * visu.n * visu_export.rate < i * (FFT_LEN / 2) * DISPLAY_BW && j < (FFT_LEN / 2); j++, count += 1) { for (count = 0, power = 0; j * visu_export.rate < visu.bars[i].limit * FFT_LEN && j < FFT_LEN / 2; j++, count += 1) {
power += visu.samples[2*j] * visu.samples[2*j] + visu.samples[2*j+1] * visu.samples[2*j+1]; power += visu.samples[2*j] * visu.samples[2*j] + visu.samples[2*j+1] * visu.samples[2*j+1];
} }
// due to sample rate, we have reached the end of the available spectrum // due to sample rate, we have reached the end of the available spectrum
@@ -674,7 +681,7 @@ static void visu_update(void) {
if (count) power /= count * 2.; if (count) power /= count * 2.;
} else if (count) { } else if (count) {
// how much of what remains do we need to add // how much of what remains do we need to add
float ratio = j - (float) (i * DISPLAY_BW * (FFT_LEN / 2)) / (float) (visu.n * visu_export.rate); float ratio = j - (visu.bars[i].limit * FFT_LEN) / rate;
power += (visu.samples[2*j] * visu.samples[2*j] + visu.samples[2*j+1] * visu.samples[2*j+1]) * ratio; power += (visu.samples[2*j] * visu.samples[2*j] + visu.samples[2*j+1] * visu.samples[2*j+1]) * ratio;
// normalize accumulated data // normalize accumulated data
@@ -685,9 +692,9 @@ 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-1].current = 32 * (0.01667f*10*(log10f(power) - log10f(FFT_LEN/2*2)) - 0.2543f); if (power) visu.bars[i].current = 32 * (0.01667f*10*(log10f(power) - log10f(FFT_LEN/2*2)) - 0.2543f);
if (visu.bars[i-1].current > 31) visu.bars[i-1].current = 31; if (visu.bars[i].current > 31) visu.bars[i].current = 31;
else if (visu.bars[i-1].current < 0) visu.bars[i-1].current = 0; else if (visu.bars[i].current < 0) visu.bars[i].current = 0;
} }
} }
} }
@@ -715,6 +722,22 @@ static void visu_update(void) {
} }
} }
/****************************************************************************************
* Visu packet handler
*/
void spectrum_limits(int min, int n, int pos) {
if (n / 2) {
int i;
float step = (DISPLAY_BW - min) * visu.spectrum_scale / (n/2);
visu.bars[pos].limit = min + step;
for (i = 1; i < n/2; i++) visu.bars[pos+i].limit = visu.bars[pos+i-1].limit + step;
spectrum_limits(visu.bars[pos + n/2 - 1].limit, n/2, pos + n/2);
} else {
visu.bars[pos].limit = DISPLAY_BW;
}
}
/**************************************************************************************** /****************************************************************************************
* Visu packet handler * Visu packet handler
*/ */
@@ -737,31 +760,38 @@ static void visu_handler( u8_t *data, int len) {
if (visu.row >= SB_HEIGHT) display->clear(false, true, visu.col, visu.row, visu.col + visu.width - 1, visu.row - visu.height - 1); if (visu.row >= SB_HEIGHT) display->clear(false, true, visu.col, visu.row, visu.col + visu.width - 1, visu.row - visu.height - 1);
if (visu.mode) { if (visu.mode) {
pkt->width = htonl(pkt->width); if (pkt->count >= 4) {
pkt->height = htonl(pkt->height);
pkt->row = htonl(pkt->row);
pkt->col = htonl(pkt->col);
if (pkt->width > 0 && pkt->count >= 4) {
// small visu, then go were we are told to // small visu, then go were we are told to
visu.width = pkt->width; 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.height = pkt->height ? pkt->height : SB_HEIGHT;
visu.col = pkt->col < 0 ? display->width + pkt->col : pkt->col; visu.col = pkt->col < 0 ? display->width + pkt->col : pkt->col;
visu.row = pkt->row < 0 ? display->height + pkt->row : pkt->row; visu.row = pkt->row < 0 ? display->height + pkt->row : pkt->row;
visu.border = htonl(pkt->border); visu.border = htonl(pkt->border);
bars = htonl(pkt->small_bars); bars = htonl(pkt->bars);
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.width = display->width; visu.width = display->width;
visu.height = display->height > SB_HEIGHT ? display->height - SB_HEIGHT : display->height; visu.height = display->height > SB_HEIGHT ? display->height - SB_HEIGHT : display->height;
visu.col = visu.border = 0; visu.col = visu.border = 0;
visu.row = display->height - visu.height; visu.row = display->height - visu.height;
// already in CPU order bars = htonl(pkt->full.bars);
bars = pkt->full_bars; visu.spectrum_scale = htonl(pkt->full.spectrum_scale) / 100.;
} }
// try to adapt to what we have // try to adapt to what we have
visu.n = visu.mode == VISU_VUMETER ? 2 : (bars ? bars : MAX_BARS); if (visu.mode == 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);
} else {
visu.n = 2;
}
do { do {
visu.bar_width = (visu.width - visu.border - visu.bar_gap * (visu.n - 1)) / visu.n; visu.bar_width = (visu.width - visu.border - visu.bar_gap * (visu.n - 1)) / visu.n;
if (visu.bar_width > 0) break; if (visu.bar_width > 0) break;
@@ -784,7 +814,7 @@ static void visu_handler( u8_t *data, int len) {
display->clear(false, true, visu.col, visu.row, visu.col + visu.width - 1, visu.row - visu.height - 1); display->clear(false, true, visu.col, visu.row, visu.col + visu.width - 1, visu.row - visu.height - 1);
LOG_INFO("Visualizer with %u bars of width %d:%d:%d:%d (%w:%u,h:%u,c:%u,r:%u)", visu.n, visu.bar_border, visu.bar_width, visu.bar_gap, visu.border, visu.width, visu.height, visu.col, visu.row); LOG_INFO("Visualizer with %u bars of width %d:%d:%d:%d (%w:%u,h:%u,c:%u,r:%u,s:%.02f)", visu.n, visu.bar_border, visu.bar_width, visu.bar_gap, visu.border, visu.width, visu.height, visu.col, visu.row, visu.spectrum_scale);
} else { } else {
LOG_INFO("Stopping visualizer"); LOG_INFO("Stopping visualizer");
} }

Binary file not shown.

View File

@@ -16,6 +16,7 @@ my $VISUALIZER_SPECTRUM_ANALYZER = 2;
my $VISUALIZER_WAVEFORM = 3; my $VISUALIZER_WAVEFORM = 3;
my $width = $prefs->get('width') || 128; my $width = $prefs->get('width') || 128;
my $spectrum_scale = $prefs->get('spectrum_scale') || 0.5;
my @modes = ( my @modes = (
# mode 0 # mode 0
@@ -55,7 +56,7 @@ my @modes = (
{ desc => ['VISUALIZER_SPECTRUM_ANALYZER_SMALL'], { desc => ['VISUALIZER_SPECTRUM_ANALYZER_SMALL'],
bar => 0, secs => 0, width => $width, _width => -32, bar => 0, secs => 0, width => $width, _width => -32,
# extra parameters (width, height, col (< 0 = from right), row (< 0 = from bottom), bars, left space) # extra parameters (width, height, col (< 0 = from right), row (< 0 = from bottom), bars, left space)
params => [$VISUALIZER_SPECTRUM_ANALYZER, 32, 32, -32, 0, 2, 6] }, params => [$VISUALIZER_SPECTRUM_ANALYZER, 32, 32, -32, 0, 2, 6, $spectrum_scale] },
# mode 9 # mode 9
{ desc => ['VISUALIZER_VUMETER'], { desc => ['VISUALIZER_VUMETER'],
bar => 0, secs => 0, width => $width, bar => 0, secs => 0, width => $width,
@@ -64,7 +65,7 @@ my @modes = (
{ 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, 16] }, params => [$VISUALIZER_SPECTRUM_ANALYZER, 16, $spectrum_scale] },
# mode 11 # mode 11
{ desc => ['VISUALIZER_VUMETER', 'AND', 'ELAPSED'], { desc => ['VISUALIZER_VUMETER', 'AND', 'ELAPSED'],
bar => 0, secs => 1, width => $width, bar => 0, secs => 1, width => $width,
@@ -73,7 +74,7 @@ my @modes = (
{ 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, 16] }, params => [$VISUALIZER_SPECTRUM_ANALYZER, 16, $spectrum_scale] },
# mode 13 # mode 13
{ desc => ['VISUALIZER_VUMETER', 'AND', 'REMAINING'], { desc => ['VISUALIZER_VUMETER', 'AND', 'REMAINING'],
bar => 0, secs => -1, width => $width, bar => 0, secs => -1, width => $width,
@@ -82,7 +83,7 @@ my @modes = (
{ 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, 16] }, params => [$VISUALIZER_SPECTRUM_ANALYZER, 16, $spectrum_scale] },
); );
@@ -135,14 +136,6 @@ sub displayHeight {
return 32; return 32;
} }
sub updateWidth {
my ($display, $width) = @_;
foreach my $mode (@{$display->modes}) {
$mode->{width} = $width + 1 + $mode->{_width} || 0;
}
}
sub vfdmodel { sub vfdmodel {
return 'graphic-'.$width.'x32'; return 'graphic-'.$width.'x32';
} }

View File

@@ -6,6 +6,11 @@
<input type="text" class="stdedit" name="pref_width" id="pref_width" value="[% prefs.pref_width %]" size="3"> <input type="text" class="stdedit" name="pref_width" id="pref_width" value="[% prefs.pref_width %]" size="3">
[% END %] [% END %]
[% WRAPPER setting title="PLUGIN_SQUEEZEESP32_SPECTRUM_SCALE" desc="PLUGIN_SQUEEZEESP32_SPECTRUM_SCALE_DESC" %]
<input type="number" min="10" max= "50" step="5" class="stdedit" name="pref_spectrum_scale" id="pref_spectrum_scale" value="[% prefs.pref_spectrum_scale %]" size="3">
[% END %]
</div> </div>
[% PROCESS settings/footer.html %] [% PROCESS settings/footer.html %]

View File

@@ -10,6 +10,7 @@ my $prefs = preferences('plugin.squeezeesp32');
$prefs->init({ $prefs->init({
width => 128, width => 128,
spectrum_scale => 50,
}); });
my $log = Slim::Utils::Log->addLogCategory({ my $log = Slim::Utils::Log->addLogCategory({

View File

@@ -17,13 +17,14 @@ sub page {
} }
sub prefs { sub prefs {
return (preferences('plugin.SqueezeESP32'), qw(width)); return (preferences('plugin.SqueezeESP32'), qw(width spectrum_scale));
} }
sub handler { sub handler {
my ($class, $client, $params, $callback, @args) = @_; my ($class, $client, $params, $callback, @args) = @_;
$callback->($client, $params, $class->SUPER::handler($client, $params), @args); $callback->($client, $params, $class->SUPER::handler($client, $params), @args);
$client->update();
} }

View File

@@ -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.10</version> <version>0.11</version>
<creator>Philippe</creator> <creator>Philippe</creator>
</extensions> </extensions>

View File

@@ -9,3 +9,11 @@ PLUGIN_SQUEEZEESP32_DESC
PLUGIN_SQUEEZEESP32_WIDTH PLUGIN_SQUEEZEESP32_WIDTH
EN Screen width EN Screen width
PLUGIN_SQUEEZEESP32_SPECTRUM_SCALE
EN Spectrum scale
PLUGIN_SQUEEZEESP32_SPECTRUM_SCALE_DESC
EN Sets the scale factor % of spectrum visualizer by halves for better representation.
EN For example, 50 means that 50% of spectrum is displayed in 1/2 of the screen, so it's linear...
EN But 25 means that only 25% of spectrum is displayed in 1/2 of the screen, so it's a sort of log

View File

@@ -1,10 +1,10 @@
<?xml version='1.0' standalone='yes'?> <?xml version='1.0' standalone='yes'?>
<extensions> <extensions>
<plugins> <plugins>
<plugin version="0.10" name="SqueezeESP32" minTarget="7.5" maxTarget="*"> <plugin version="0.11" 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>5a35a7b821e887baf869535f113b8b55bbc52a54</sha> <sha>b923bd7dd412d1897eb8be2dec862f91f1e36dc4</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>