plugins: Oscilloscope & VU Meter: Support USB audio

Also show current mixer frequency in title of VU meter,
and adjust the menu title from "VU Meter Menu" to just
"VU Meter"

Change-Id: I5bf8f55a3c9874618cac939fe32a611ac96f52ff
This commit is contained in:
Christian Soffke 2025-11-23 23:33:19 +01:00
parent 0551c4a780
commit 4095b13d52
4 changed files with 91 additions and 27 deletions

View file

@ -62,6 +62,10 @@
#include "usbstack/usb_hid.h" #include "usbstack/usb_hid.h"
#endif #endif
#ifdef USB_ENABLE_AUDIO
#include "usbstack/usb_audio.h"
#endif
#define WRAPPER(_x_) _x_ ## _wrapper #define WRAPPER(_x_) _x_ ## _wrapper
#if (CONFIG_PLATFORM & PLATFORM_HOSTED) #if (CONFIG_PLATFORM & PLATFORM_HOSTED)
@ -845,6 +849,9 @@ static const struct plugin_api rockbox_api = {
add_playbacklog, add_playbacklog,
&device_battery_tables, &device_battery_tables,
yesno_pop_confirm, yesno_pop_confirm,
#ifdef USB_ENABLE_AUDIO
usb_audio_get_playing,
#endif
}; };
static int plugin_buffer_handle; static int plugin_buffer_handle;

View file

@ -994,6 +994,9 @@ struct plugin_api {
void (*add_playbacklog)(struct mp3entry *id3); void (*add_playbacklog)(struct mp3entry *id3);
struct battery_tables_t *device_battery_tables; struct battery_tables_t *device_battery_tables;
bool (*yesno_pop_confirm)(const char* text); bool (*yesno_pop_confirm)(const char* text);
#ifdef USB_ENABLE_AUDIO
bool (*usb_audio_get_playing)(void);
#endif
}; };
/* plugin header */ /* plugin header */

View file

@ -763,6 +763,8 @@ static bool one_frame_paused = false; /* Allow one frame to be drawn when paused
static long osc_delay; /* delay in 100ths of a tick */ static long osc_delay; /* delay in 100ths of a tick */
static long osc_delay_error; /* delay fraction error accumulator */ static long osc_delay_error; /* delay fraction error accumulator */
static enum pcm_mixer_channel channel;
/* implementation */ /* implementation */
@ -938,7 +940,7 @@ static int last_right;
static void get_peaks(int *left, int *right) static void get_peaks(int *left, int *right)
{ {
static struct pcm_peaks peaks; static struct pcm_peaks peaks;
rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK, rb->mixer_channel_calculate_peaks(channel,
&peaks); &peaks);
*left = peaks.left; *left = peaks.left;
*right = peaks.right; *right = peaks.right;
@ -1501,7 +1503,7 @@ static long anim_waveform_horizontal(void)
long cur_tick = *rb->current_tick; long cur_tick = *rb->current_tick;
if (rb->mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_PLAYING) if (rb->mixer_channel_status(channel) != CHANNEL_PLAYING)
{ {
osd_lcd_update_prepare(); osd_lcd_update_prepare();
rb->lcd_hline(0, LCD_WIDTH-1, 1*LCD_HEIGHT/4); rb->lcd_hline(0, LCD_WIDTH-1, 1*LCD_HEIGHT/4);
@ -1695,7 +1697,7 @@ static long anim_waveform_vertical(void)
long cur_tick = *rb->current_tick; long cur_tick = *rb->current_tick;
if (rb->mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_PLAYING) if (rb->mixer_channel_status(channel) != CHANNEL_PLAYING)
{ {
osd_lcd_update_prepare(); osd_lcd_update_prepare();
rb->lcd_vline(1*LCD_WIDTH/4, 0, LCD_HEIGHT-1); rb->lcd_vline(1*LCD_WIDTH/4, 0, LCD_HEIGHT-1);
@ -1838,7 +1840,7 @@ static long anim_waveform_vertical(void)
static void anim_waveform_exit(void) static void anim_waveform_exit(void)
{ {
/* Remove any buffer hook */ /* Remove any buffer hook */
rb->mixer_channel_set_buffer_hook(PCM_MIXER_CHAN_PLAYBACK, NULL); rb->mixer_channel_set_buffer_hook(channel, NULL);
#ifdef HAVE_SCHEDULER_BOOSTCTRL #ifdef HAVE_SCHEDULER_BOOSTCTRL
/* Remove our boost */ /* Remove our boost */
rb->cancel_cpu_boost(); rb->cancel_cpu_boost();
@ -1906,7 +1908,7 @@ static void graphmode_setup(void)
#ifdef OSCILLOSCOPE_GRAPHMODE #ifdef OSCILLOSCOPE_GRAPHMODE
if (osc.graphmode == GRAPH_WAVEFORM) if (osc.graphmode == GRAPH_WAVEFORM)
{ {
rb->mixer_channel_set_buffer_hook(PCM_MIXER_CHAN_PLAYBACK, rb->mixer_channel_set_buffer_hook(channel,
waveform_buffer_callback); waveform_buffer_callback);
#ifdef HAVE_SCHEDULER_BOOSTCTRL #ifdef HAVE_SCHEDULER_BOOSTCTRL
rb->trigger_cpu_boost(); /* Just looks better */ rb->trigger_cpu_boost(); /* Just looks better */
@ -1914,7 +1916,7 @@ static void graphmode_setup(void)
} }
else else
{ {
rb->mixer_channel_set_buffer_hook(PCM_MIXER_CHAN_PLAYBACK, rb->mixer_channel_set_buffer_hook(channel,
NULL); NULL);
#ifdef HAVE_SCHEDULER_BOOSTCTRL #ifdef HAVE_SCHEDULER_BOOSTCTRL
rb->cancel_cpu_boost(); rb->cancel_cpu_boost();
@ -2005,6 +2007,21 @@ static void osc_setup(void)
graphmode_setup(); graphmode_setup();
} }
#ifdef USB_ENABLE_AUDIO
void switch_channel(enum pcm_mixer_channel new_channel)
{
/* Remove any buffer hook */
rb->mixer_channel_set_buffer_hook(channel, NULL);
channel = new_channel;
#ifdef OSCILLOSCOPE_GRAPHMODE
if (osc.graphmode == GRAPH_WAVEFORM)
rb->mixer_channel_set_buffer_hook(channel, waveform_buffer_callback);
#endif
}
#endif /* USB_ENABLE_AUDIO */
enum plugin_status plugin_start(const void* parameter) enum plugin_status plugin_start(const void* parameter)
{ {
bool exit = false; bool exit = false;
@ -2012,10 +2029,25 @@ enum plugin_status plugin_start(const void* parameter)
int lastbutton = BUTTON_NONE; int lastbutton = BUTTON_NONE;
#endif #endif
channel = PCM_MIXER_CHAN_PLAYBACK;
osc_setup(); osc_setup();
while (!exit) while (!exit)
{ {
#ifdef USB_ENABLE_AUDIO
if (rb->usb_audio_get_playing())
{
if (channel != PCM_MIXER_CHAN_USBAUDIO)
switch_channel(PCM_MIXER_CHAN_USBAUDIO);
}
else
{
if (channel != PCM_MIXER_CHAN_PLAYBACK)
switch_channel(PCM_MIXER_CHAN_PLAYBACK);
}
#endif /* USB_ENABLE_AUDIO */
long delay = oscilloscope_draw(); long delay = oscilloscope_draw();
if (delay <= 0) if (delay <= 0)

View file

@ -666,7 +666,7 @@ static bool vu_meter_menu(void)
bool menu_quit = false; bool menu_quit = false;
bool exit = false; bool exit = false;
MENUITEM_STRINGLIST(menu,"VU Meter Menu",NULL,"Meter Type","Scale", MENUITEM_STRINGLIST(menu,"VU Meter",NULL,"Meter Type","Scale",
"Minimeters","Decay Speed","Playback Control", "Minimeters","Decay Speed","Playback Control",
"Quit"); "Quit");
@ -811,14 +811,8 @@ static void draw_digital_minimeters(void) {
#endif #endif
} }
static void analog_meter(void) { static void draw_analog_meter(uint32_t left_peak, uint32_t right_peak)
{
static struct pcm_peaks peaks;
rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
&peaks);
#define left_peak peaks.left
#define right_peak peaks.right
if(vumeter_settings.analog_use_db_scale) { if(vumeter_settings.analog_use_db_scale) {
left_needle_top_x = analog_db_scale[left_peak * half_width / MAX_PEAK]; left_needle_top_x = analog_db_scale[left_peak * half_width / MAX_PEAK];
right_needle_top_x = analog_db_scale[right_peak * half_width / MAX_PEAK] + half_width; right_needle_top_x = analog_db_scale[right_peak * half_width / MAX_PEAK] + half_width;
@ -867,13 +861,8 @@ static void analog_meter(void) {
} }
} }
static void digital_meter(void) { static void draw_digital_meter(uint32_t left_peak, uint32_t right_peak)
static struct pcm_peaks peaks; {
rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
&peaks);
#define left_peak peaks.left
#define right_peak peaks.right
if(vumeter_settings.digital_use_db_scale) { if(vumeter_settings.digital_use_db_scale) {
num_left_leds = digital_db_scale[left_peak * 44 / MAX_PEAK]; num_left_leds = digital_db_scale[left_peak * 44 / MAX_PEAK];
num_right_leds = digital_db_scale[right_peak * 44 / MAX_PEAK]; num_right_leds = digital_db_scale[right_peak * 44 / MAX_PEAK];
@ -933,13 +922,37 @@ static void digital_meter(void) {
rb->lcd_hline(0,LCD_WIDTH-1,half_height+3); rb->lcd_hline(0,LCD_WIDTH-1,half_height+3);
} }
static void draw_title(void)
{
static unsigned int sampr;
static int x;
static char title[16];
if (sampr != rb->mixer_get_frequency())
{
sampr = rb->mixer_get_frequency();
if ((sampr % 1000) < 100)
rb->snprintf(title, sizeof title, "VU %d kHz",
sampr / 1000);
else
rb->snprintf(title, sizeof title, "VU %d.%u kHz",
sampr / 1000, (sampr % 1000) / 100);
rb->font_getstringsize(title, &x, NULL, FONT_SYSFIXED);
x = half_width - (x/2); /* centered */
}
rb->lcd_putsxy(x, 0, title);
}
static void vu_meter_cleanup(void) static void vu_meter_cleanup(void)
{ {
/* Turn on backlight timeout (revert to settings) */ /* Turn on backlight timeout (revert to settings) */
backlight_use_settings(); backlight_use_settings();
} }
enum plugin_status plugin_start(const void* parameter) { enum plugin_status plugin_start(const void* parameter)
{
static struct pcm_peaks peaks;
int button; int button;
#if defined(VUMETER_HELP_PRE) || defined(VUMETER_MENU_PRE) #if defined(VUMETER_HELP_PRE) || defined(VUMETER_MENU_PRE)
int lastbutton = BUTTON_NONE; int lastbutton = BUTTON_NONE;
@ -964,12 +977,21 @@ enum plugin_status plugin_start(const void* parameter) {
{ {
rb->lcd_clear_display(); rb->lcd_clear_display();
rb->lcd_putsxy(half_width-23, 0, "VU Meter"); draw_title();
if(vumeter_settings.meter_type==ANALOG) #ifdef USB_ENABLE_AUDIO
analog_meter(); if (rb->usb_audio_get_playing())
rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_USBAUDIO,
&peaks);
else else
digital_meter(); #endif
rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
&peaks);
if(vumeter_settings.meter_type == ANALOG)
draw_analog_meter(peaks.left, peaks.right);
else
draw_digital_meter(peaks.left, peaks.right);
rb->lcd_update(); rb->lcd_update();