diff --git a/src/gtk_ui.c b/src/gtk_ui.c index 26bbf02..2a44eb5 100644 --- a/src/gtk_ui.c +++ b/src/gtk_ui.c @@ -364,6 +364,15 @@ extern gboolean toogle_absolute_windowing_callback(GtkToggleToolButton* button, return FALSE; } +static gboolean io_callback(GIOChannel *gio_channel, GIOCondition giocondition, gpointer data) +{ + struct io_callback_data* cb = (struct io_callback_data*)data; + + cb->f(cb->context); + + return TRUE; +} + extern void ui_configure(struct view_s *v) { @@ -491,6 +500,12 @@ void ui_loop_quit() gtk_main_quit(); } +void ui_add_io_callback(int fd, struct io_callback_data* cb) +{ + GIOChannel* giochannel_strm = g_io_channel_unix_new(fd); + g_io_add_watch(giochannel_strm, G_IO_IN, io_callback, cb); +} + bool gtk_ui_save_png(struct view_s* v, const char* filename) { diff --git a/src/gtk_ui.h b/src/gtk_ui.h index 2e7750e..c4bdd66 100644 --- a/src/gtk_ui.h +++ b/src/gtk_ui.h @@ -4,6 +4,12 @@ struct view_s; struct view_ui_params_s; struct view_settings_s; +typedef void (*io_callback_function)(void *); + +struct io_callback_data { + io_callback_function f; + void* context; +}; extern void ui_rgbbuffer_disconnect(struct view_s* v); extern void ui_rgbbuffer_connect(struct view_s* v, int rgbw, int rgbh, int rgbstr, unsigned char* buf); @@ -21,6 +27,7 @@ extern void ui_loop_quit(); extern void ui_configure(struct view_s* v); extern void ui_trigger_redraw(struct view_s* v); +void ui_add_io_callback(int fd, struct io_callback_data* cb); extern bool gtk_ui_save_png(struct view_s* v, const char* filename); diff --git a/src/main.c b/src/main.c index 6c9d19f..29d7203 100644 --- a/src/main.c +++ b/src/main.c @@ -4,9 +4,16 @@ * a BSD-style license which can be found in the LICENSE file. */ +#include "num/multind.h" #include #include +#if defined __has_include +#if __has_include ("misc/stream.h") +#define HAS_BART_STREAM +#endif +#endif + #include "misc/misc.h" #include "misc/mmio.h" #include "misc/opts.h" @@ -29,6 +36,7 @@ int main(int argc, char* argv[argc]) { int count; const char** in_files; + int realtime = -1; struct arg_s args[] = { @@ -46,6 +54,10 @@ int main(int argc, char* argv[argc]) OPT_SELECT('T', enum color_t, &ctab, TURBO, "turbo"), OPT_SELECT('L', enum color_t, &ctab, LIPARI, "lipari"), OPT_SELECT('N', enum color_t, &ctab, NAVIA, "navia"), + +#if defined HAS_BART_STREAM + OPTL_INT(0, "real-time", &realtime, "x", "Realtime Input along axis x"), +#endif }; cmdline(&argc, argv, ARRAY_SIZE(args), args, help_str, ARRAY_SIZE(opts), opts); @@ -80,14 +92,28 @@ int main(int argc, char* argv[argc]) io_reserve_input(in_files[i]); +#if defined HAS_BART_STREAM + complex float* x = (0 <= realtime ? load_async_cfl : load_cfl)(in_files[i], DIMS, dims); +#else complex float* x = load_cfl(in_files[i], DIMS, dims); +#endif long pos[DIMS] = { 0 }; for (int i = 0; i < 3; i++) pos[i] = dims[i] / 2; + // absolute windowing for realtime. avoids access to 'unsynced' + // memory when calculating the windowing + if (0 <= realtime) { + + absolute_windowing = true; + + // don't set position for streamed dimension. + md_select_strides(DIMS, ~MD_BIT(realtime), pos, pos); + } + // FIXME: we never delete them - struct view_s* v2 = window_new(in_files[i], pos, dims, x, absolute_windowing, ctab); + struct view_s* v2 = window_new(in_files[i], pos, dims, x, absolute_windowing, ctab, realtime); // If multiple files are passed on the commandline, add them to window // list. This enables sync of windowing and so on... diff --git a/src/view.c b/src/view.c index cb9660b..14a4688 100644 --- a/src/view.c +++ b/src/view.c @@ -19,6 +19,15 @@ #include "misc/png.h" #include "misc/debug.h" +#if defined __has_include +#if __has_include ("misc/stream.h") +#define HAS_BART_STREAM +#endif +#endif +#if defined HAS_BART_STREAM +#include "misc/stream.h" +#endif + #include "draw.h" #include "view.h" @@ -41,6 +50,9 @@ struct view_control_s { long strs[DIMS]; const complex float* data; + int realtime; + struct io_callback_data rt_callback; + // interpolation buffer complex float* buf; @@ -72,6 +84,9 @@ struct view_control_s { static void view_window_nosync(struct view_s* v, enum mode_t mode, double winlow, double winhigh); static void view_geom2(struct view_s* v); +static void add_rt_callback(struct view_s *ptr); +static void view_ff_realtime_position(struct view_s *v); + #if 0 static void add_text(cairo_surface_t* surface, int x, int y, int size, const char* text) { @@ -752,7 +767,7 @@ void view_window_close(struct view_s* v) struct view_s* window_new(const char* name, const long pos[DIMS], const long dims[DIMS], const complex float* x, - bool absolute_windowing, enum color_t ctab) + bool absolute_windowing, enum color_t ctab, int realtime) { struct view_s* v = create_view(name, pos, dims, x); @@ -773,6 +788,13 @@ struct view_s* window_new(const char* name, const long pos[DIMS], const long dim ui_set_params(v, v->ui_params, v->settings); + v->control->realtime = realtime; + if (0 <= realtime) { + + view_ff_realtime_position(v); + add_rt_callback(v); + } + view_release(v); return v; @@ -793,7 +815,7 @@ void window_connect_sync(struct view_s* v, struct view_s* v2) struct view_s* view_window_clone(struct view_s* v) { struct view_s* v2 = window_new(v->name, v->settings.pos, v->control->dims, v->control->data, - v->settings.absolute_windowing, v->settings.colortable); + v->settings.absolute_windowing, v->settings.colortable, v->control->realtime); window_connect_sync(v, v2); @@ -822,3 +844,50 @@ void view_toggle_plot(struct view_s* v) ui_trigger_redraw(v); } + +static void view_ff_realtime_position(struct view_s *v) +{ +#if defined HAS_BART_STREAM + struct view_control_s* control = v->control; + stream_t s = stream_lookup(control->data); + + if (NULL == s) + return; + + stream_fetch(s); + + long pos[DIMS] = { 0 }; + stream_get_latest_pos(s, DIMS, pos); + + long new_pos = pos[control->realtime]; + + if (new_pos > v->settings.pos[control->realtime]) { + + v->settings.pos[control->realtime] = new_pos; + ui_set_params(v, v->ui_params, v->settings); + view_sync(v); + + control->rgb_invalid = true; + view_refresh(v); + } +#endif +} + +static void add_rt_callback(struct view_s *v) +{ +#if defined HAS_BART_STREAM + stream_t s = stream_lookup(v->control->data); + + if (NULL == s) + return; + + int fd = stream_get_fd(s); + + if (0 <= fd) { + + v->control->rt_callback.context = v; + v->control->rt_callback.f = (io_callback_function)view_ff_realtime_position; + ui_add_io_callback(fd, &v->control->rt_callback); + } +#endif +} diff --git a/src/view.h b/src/view.h index 58747d2..ff1bf2c 100644 --- a/src/view.h +++ b/src/view.h @@ -70,7 +70,7 @@ struct view_s { // setup etc -extern struct view_s* window_new(const char* name, const long pos[DIMS], const long dims[DIMS], const _Complex float* x, _Bool absolute_windowing, enum color_t ctab); +extern struct view_s* window_new(const char* name, const long pos[DIMS], const long dims[DIMS], const _Complex float* x, _Bool absolute_windowing, enum color_t ctab, int realtime); extern void window_connect_sync(struct view_s* a, struct view_s* b);