This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch main
in repository eradio.
View the commit online.
commit de6d788a9f3d8497bf854463f34958d3e61449b0
Author: politebot <[email protected]>
AuthorDate: Wed Oct 22 16:39:10 2025 -0500
Add GOOM visualizer
---
src/Makefile.am | 4 +-
src/appdata.h | 6 +++
src/main.c | 3 ++
src/radio_player.c | 24 +++++++++
src/ui.c | 2 +
src/visualizer.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/visualizer.h | 13 +++++
7 files changed, 203 insertions(+), 2 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index dd66cad..f8849b2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,7 @@
bin_PROGRAMS = eradio
-eradio_SOURCES = main.c ui.c radio_player.c station_list.c http.c favorites.c \
- appdata.h ui.h radio_player.h station_list.h http.h favorites.h
+eradio_SOURCES = main.c ui.c radio_player.c station_list.c http.c favorites.c visualizer.c \
+ appdata.h ui.h radio_player.h station_list.h http.h favorites.h visualizer.h
eradio_CFLAGS = $(EFL_CFLAGS) $(LIBXML_CFLAGS)
eradio_LDADD = $(EFL_LIBS) $(LIBXML_LIBS)
diff --git a/src/appdata.h b/src/appdata.h
index bcc4c48..c80bfbb 100644
--- a/src/appdata.h
+++ b/src/appdata.h
@@ -36,6 +36,7 @@ typedef struct _AppData
Evas_Object *controls_toolbar;
Elm_Object_Item *play_pause_item;
Elm_Object_Item *stop_item;
+ Elm_Object_Item *visualizer_item;
Evas_Object *separator;
Evas_Object *statusbar;
Evas_Object *volume_slider;
@@ -58,4 +59,9 @@ typedef struct _AppData
ViewMode view_mode;
int search_offset;
int displayed_stations_count;
+
+ // Visualizer
+ Evas_Object *visualizer_win;
+ Evas_Object *visualizer_emotion;
+ Eina_Bool visualizer_active;
} AppData;
diff --git a/src/main.c b/src/main.c
index 09de68f..c3eeeef 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3,6 +3,7 @@
#include "radio_player.h"
#include "http.h"
#include "favorites.h"
+#include "visualizer.h"
EAPI_MAIN int
elm_main(int argc, char **argv)
@@ -17,11 +18,13 @@ elm_main(int argc, char **argv)
http_init(&ad);
ui_update_server_list(&ad);
radio_player_init(&ad);
+ visualizer_init(&ad);
elm_run();
http_shutdown();
radio_player_shutdown();
+ visualizer_shutdown(&ad);
favorites_shutdown(&ad);
return 0;
diff --git a/src/radio_player.c b/src/radio_player.c
index 9f0022e..36a2d54 100644
--- a/src/radio_player.c
+++ b/src/radio_player.c
@@ -1,5 +1,6 @@
#include "radio_player.h"
#include "ui.h"
+#include "visualizer.h"
static Ecore_Timer *stream_error_timer = NULL;
static Ecore_Timer *audio_progress_timer = NULL;
@@ -149,6 +150,9 @@ radio_player_play(AppData *ad, const char *url, const char *station_name)
emotion_object_file_set(ad->emotion, url);
emotion_object_play_set(ad->emotion, EINA_TRUE);
ad->playing = EINA_TRUE;
+
+ // Start visualizer playback if active
+ visualizer_play(ad);
if (ad->play_pause_item)
elm_toolbar_item_icon_set(ad->play_pause_item, "media-playback-pause");
@@ -156,6 +160,9 @@ radio_player_play(AppData *ad, const char *url, const char *station_name)
if (current_station_name)
elm_object_text_set(ad->statusbar, current_station_name);
+ // Update visualizer with new station
+ visualizer_set_station(ad, url);
+
// Reset position tracking
last_position = 0.0;
@@ -172,6 +179,9 @@ radio_player_stop(AppData *ad)
emotion_object_position_set(ad->emotion, 0.0);
ad->playing = EINA_FALSE;
+ // Stop visualizer if active
+ visualizer_stop(ad);
+
// Cancel all timers
if (stream_error_timer)
{
@@ -202,6 +212,13 @@ radio_player_toggle_pause(AppData *ad)
{
ad->playing = !ad->playing;
emotion_object_play_set(ad->emotion, ad->playing);
+
+ // Sync visualizer with playback state
+ if (ad->playing)
+ visualizer_play(ad);
+ else
+ visualizer_pause(ad);
+
if (ad->play_pause_item)
{
if (ad->playing)
@@ -224,3 +241,10 @@ _stop_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info)
AppData *ad = data;
radio_player_stop(ad);
}
+
+void
+_visualizer_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info)
+{
+ AppData *ad = data;
+ visualizer_toggle(ad);
+}
diff --git a/src/ui.c b/src/ui.c
index 0fab782..792b589 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -16,6 +16,7 @@ static void _tb_url_clicked_cb(void *data, Evas_Object *obj, void *event_info);
// Forward declarations for callbacks
void _play_pause_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info);
void _stop_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info);
+void _visualizer_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info);
void _search_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info);
void _search_entry_activated_cb(void *data, Evas_Object *obj, void *event_info);
void _list_item_selected_cb(void *data, Evas_Object *obj, void *event_info);
@@ -250,6 +251,7 @@ ui_create(AppData *ad)
ad->play_pause_item = elm_toolbar_item_append(ad->controls_toolbar, "media-playback-start", "Play/Pause", _play_pause_btn_clicked_cb, ad);
ad->stop_item = elm_toolbar_item_append(ad->controls_toolbar, "media-playback-stop", "Stop", _stop_btn_clicked_cb, ad);
+ ad->visualizer_item = elm_toolbar_item_append(ad->controls_toolbar, "media-video", "Visualizer", _visualizer_btn_clicked_cb, ad);
evas_object_smart_callback_add(ad->search_btn, "clicked", _search_btn_clicked_cb, ad);
evas_object_smart_callback_add(ad->search_entry, "activated", _search_entry_activated_cb, ad);
diff --git a/src/visualizer.c b/src/visualizer.c
new file mode 100644
index 0000000..c1cd736
--- /dev/null
+++ b/src/visualizer.c
@@ -0,0 +1,153 @@
+#include "visualizer.h"
+#include "ui.h"
+
+static void _visualizer_win_del_cb(void *data, Evas_Object *obj, void *event_info);
+static void _visualizer_title_changed_cb(void *data, Evas_Object *obj, void *event_info);
+
+void
+visualizer_init(AppData *ad)
+{
+ ad->visualizer_win = NULL;
+ ad->visualizer_emotion = NULL;
+ ad->visualizer_active = EINA_FALSE;
+}
+
+static void
+_visualizer_win_del_cb(void *data, Evas_Object *obj, void *event_info)
+{
+ AppData *ad = data;
+ visualizer_hide(ad);
+}
+
+static void
+_visualizer_title_changed_cb(void *data, Evas_Object *obj, void *event_info)
+{
+ AppData *ad = data;
+ const char *title = emotion_object_title_get(obj);
+
+ if (ad->visualizer_win && title && strlen(title) > 0)
+ {
+ char window_title[256];
+ snprintf(window_title, sizeof(window_title), "eradio Visualizer - %s", title);
+ elm_win_title_set(ad->visualizer_win, window_title);
+ }
+}
+
+void
+visualizer_show(AppData *ad)
+{
+ if (ad->visualizer_active)
+ return;
+
+ // Create visualizer window
+ ad->visualizer_win = elm_win_add(NULL, "eradio_visualizer", ELM_WIN_BASIC);
+ elm_win_title_set(ad->visualizer_win, "eradio Visualizer");
+ elm_win_autodel_set(ad->visualizer_win, EINA_TRUE);
+ evas_object_smart_callback_add(ad->visualizer_win, "delete,request", _visualizer_win_del_cb, ad);
+
+ // Set a reasonable default size
+ evas_object_resize(ad->visualizer_win, 640, 480);
+
+ // Create emotion object for visualization
+ ad->visualizer_emotion = emotion_object_add(ad->visualizer_win);
+
+ // Set GOOM visualization
+ emotion_object_vis_set(ad->visualizer_emotion, EMOTION_VIS_GOOM);
+
+ // Add title change callback for window title updates
+ evas_object_smart_callback_add(ad->visualizer_emotion, "title_change", _visualizer_title_changed_cb, ad);
+
+ // Make emotion object fill the window
+ evas_object_size_hint_weight_set(ad->visualizer_emotion, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(ad->visualizer_emotion, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_win_resize_object_add(ad->visualizer_win, ad->visualizer_emotion);
+ evas_object_show(ad->visualizer_emotion);
+
+ // If there's already a station playing, connect the visualizer to it
+ if (ad->playing && ad->emotion)
+ {
+ const char *current_url = emotion_object_file_get(ad->emotion);
+ if (current_url)
+ {
+ emotion_object_file_set(ad->visualizer_emotion, current_url);
+ emotion_object_play_set(ad->visualizer_emotion, EINA_TRUE);
+ }
+ }
+
+ ad->visualizer_active = EINA_TRUE;
+ evas_object_show(ad->visualizer_win);
+}
+
+void
+visualizer_hide(AppData *ad)
+{
+ if (!ad->visualizer_active)
+ return;
+
+ if (ad->visualizer_emotion)
+ {
+ emotion_object_play_set(ad->visualizer_emotion, EINA_FALSE);
+ evas_object_del(ad->visualizer_emotion);
+ ad->visualizer_emotion = NULL;
+ }
+
+ if (ad->visualizer_win)
+ {
+ evas_object_del(ad->visualizer_win);
+ ad->visualizer_win = NULL;
+ }
+
+ ad->visualizer_active = EINA_FALSE;
+}
+
+void
+visualizer_toggle(AppData *ad)
+{
+ if (ad->visualizer_active)
+ visualizer_hide(ad);
+ else
+ visualizer_show(ad);
+}
+
+void
+visualizer_set_station(AppData *ad, const char *url)
+{
+ if (!ad->visualizer_active || !ad->visualizer_emotion || !url)
+ return;
+
+ emotion_object_file_set(ad->visualizer_emotion, url);
+}
+
+void
+visualizer_play(AppData *ad)
+{
+ if (!ad->visualizer_active || !ad->visualizer_emotion)
+ return;
+
+ emotion_object_play_set(ad->visualizer_emotion, EINA_TRUE);
+}
+
+void
+visualizer_pause(AppData *ad)
+{
+ if (!ad->visualizer_active || !ad->visualizer_emotion)
+ return;
+
+ emotion_object_play_set(ad->visualizer_emotion, EINA_FALSE);
+}
+
+void
+visualizer_stop(AppData *ad)
+{
+ if (!ad->visualizer_active || !ad->visualizer_emotion)
+ return;
+
+ emotion_object_play_set(ad->visualizer_emotion, EINA_FALSE);
+ emotion_object_position_set(ad->visualizer_emotion, 0.0);
+}
+
+void
+visualizer_shutdown(AppData *ad)
+{
+ visualizer_hide(ad);
+}
\ No newline at end of file
diff --git a/src/visualizer.h b/src/visualizer.h
new file mode 100644
index 0000000..9c44f7d
--- /dev/null
+++ b/src/visualizer.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "appdata.h"
+
+void visualizer_init(AppData *ad);
+void visualizer_show(AppData *ad);
+void visualizer_hide(AppData *ad);
+void visualizer_toggle(AppData *ad);
+void visualizer_set_station(AppData *ad, const char *url);
+void visualizer_play(AppData *ad);
+void visualizer_pause(AppData *ad);
+void visualizer_stop(AppData *ad);
+void visualizer_shutdown(AppData *ad);
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.