diff options
author | Hanspeter Portner <dev@open-music-kontrollers.ch> | 2017-03-21 20:51:07 +0100 |
---|---|---|
committer | Hanspeter Portner <dev@open-music-kontrollers.ch> | 2017-03-21 20:51:07 +0100 |
commit | d0f3a9ac228f5798a045f75376817b43666939bd (patch) | |
tree | 324f4540c6fd7413777a75611a447412e6790107 | |
parent | f3d77a9c079754914ebe1ccdfc58d0df953be8b8 (diff) | |
download | vm.lv2-d0f3a9ac228f5798a045f75376817b43666939bd.tar.xz |
plot control values.
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | vm.c | 31 | ||||
-rw-r--r-- | vm.ttl | 4 | ||||
-rw-r--r-- | vm_ui.c | 235 |
4 files changed, 180 insertions, 92 deletions
@@ -1 +1 @@ -0.1.2845 +0.1.2847 @@ -69,6 +69,8 @@ struct _plughandle_t { bool needs_sync; bool uses_time; + int64_t off; + command_t cmds [ITEMS_MAX]; timely_t timely; @@ -661,13 +663,38 @@ run(LV2_Handle instance, uint32_t nsamples) handle->needs_recalc = false; } + //FIXME handle also inputs + for(unsigned i = 0; i < CTRL_MAX; i++) + { + if(*handle->out[i] != handle->out0[i]) + { + *handle->out[i] = handle->out0[i];; + + LV2_Atom_Forge_Frame tup_frame; + if(handle->ref) + handle->ref = lv2_atom_forge_frame_time(&handle->forge, nsamples - 1); + if(handle->ref) + handle->ref = lv2_atom_forge_tuple(&handle->forge, &tup_frame); + if(handle->ref) + handle->ref = lv2_atom_forge_int(&handle->forge, i + 10); + if(handle->ref) + handle->ref = lv2_atom_forge_float(&handle->forge, handle->out0[i]); + if(handle->ref) + lv2_atom_forge_pop(&handle->forge, &tup_frame); + } + } + + if(handle->ref) + handle->ref = lv2_atom_forge_frame_time(&handle->forge, nsamples - 1); + if(handle->ref) + handle->ref = lv2_atom_forge_long(&handle->forge, handle->off); + if(handle->ref) lv2_atom_forge_pop(&handle->forge, &frame); else lv2_atom_sequence_clear(handle->notify); - for(unsigned i = 0; i < CTRL_MAX; i++) - *handle->out[i] = handle->out0[i];; + handle->off += nsamples; } static void @@ -353,8 +353,8 @@ vm:lfo vm:graph [ a atom:Tuple ; rdf:value ( - # Phase := (Beat % Control0 ) / Control0 - 0 vm:opInput + # Phase := (Beat % Cycles) / Control0 + 2.0 # Cycles per beat vm:opPush time:beat vm:opSwap @@ -31,7 +31,10 @@ # undef Bool #endif +#define PLOT_MAX 256 + typedef struct _atom_ser_t atom_ser_t; +typedef struct _plot_t plot_t; typedef struct _plughandle_t plughandle_t; struct _atom_ser_t { @@ -44,6 +47,10 @@ struct _atom_ser_t { }; }; +struct _plot_t { + float vals [PLOT_MAX]; +}; + struct _plughandle_t { LV2_URID_Map *map; LV2_URID_Unmap *unmap; @@ -74,15 +81,22 @@ struct _plughandle_t { float in0 [CTRL_MAX]; float out0 [CTRL_MAX]; + int64_t off; + plot_t inp [CTRL_MAX]; + plot_t outp [CTRL_MAX]; + command_t cmds [ITEMS_MAX]; }; -typedef struct _desc_t desc_t; - -struct _desc_t { - const char *label; - unsigned npush; - unsigned npop; +static const char *input_labels [CTRL_MAX] = { + "Input 0:", + "Input 1:", + "Input 2:", + "Input 3:", + "Input 4:", + "Input 5:", + "Input 6:", + "Input 7:", }; static void @@ -176,26 +190,45 @@ _set_property(plughandle_t *handle, LV2_URID property) handle->atom_eventTransfer, atom); } -static bool -_tooltip_visible(struct nk_context *ctx) -{ - return nk_widget_has_mouse_click_down(ctx, NK_BUTTON_RIGHT, nk_true) - || (nk_widget_is_hovered(ctx) && nk_input_is_key_down(&ctx->input, NK_KEY_CTRL)); -} +#define VM_MIN -0x2000 +#define VM_MAX 0x1fff +#define VM_RNG (VM_MAX - VM_MIN) +#define VM_VIS (VM_RNG * 1.1f) static inline void -_draw_separator(struct nk_context *ctx, float line_width) +_draw_plot(struct nk_context *ctx, const float *vals, unsigned nvals) { - const struct nk_rect b = nk_widget_bounds(ctx); - const float x0 = b.x; - const float x1 = b.x + b.w; - const float y = b.y + b.h; struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); - nk_stroke_line(canvas, x0, y, x1, y, line_width, ctx->style.window.background); -} -#define VM_MIN -0x2000 -#define VM_MAX 0x1fff + struct nk_rect bounds; + const nk_flags states = nk_widget(&bounds, ctx); + if(states != NK_WIDGET_INVALID) + { + const struct nk_rect old_clip = canvas->clip; + + const struct nk_rect outer = nk_pad_rect(bounds, nk_vec2(-2.f, -2.f)); + nk_push_scissor(canvas, outer); + nk_fill_rect(canvas, bounds, 0.f, nk_rgb(0x22, 0x22, 0x22)); + nk_stroke_rect(canvas, bounds, 0.f, 1.f, ctx->style.window.border_color); + + float mem [PLOT_MAX*2]; + for(unsigned i = 0; i < nvals; i++) + { + const float sx = (float)i / nvals; + const float sy = vals[i] / VM_VIS; + + const float x1 = bounds.x + sx*bounds.w; + const float y1 = bounds.y + (0.5f - sy)*bounds.h; + + const unsigned i2 = i*2; + mem[i2 + 0] = x1; + mem[i2 + 1] = y1; + } + + nk_stroke_polyline(canvas, mem, PLOT_MAX, 1.f, nk_rgb(0xcc, 0xcc, 0xcc)); + nk_push_scissor(canvas, old_clip); + } +} static void _expose(struct nk_context *ctx, struct nk_rect wbounds, void *data) @@ -213,38 +246,22 @@ _expose(struct nk_context *ctx, struct nk_rect wbounds, void *data) const float wh = wbounds.h - 2*ctx->style.window.padding.y - 2*ctx->style.window.border; - nk_layout_row_dynamic(ctx, wh, 2); - if(nk_group_begin(ctx, "Controls", NK_WINDOW_TITLE | NK_WINDOW_BORDER)) - { - if(nk_tree_push(ctx, NK_TREE_NODE, "Inputs", NK_MAXIMIZED)) - { - for(unsigned i = 0; i < CTRL_MAX; i++) - { - char label [16]; - snprintf(label, 16, "Input %u:", i); - - const float old_val = handle->in0[i]; - nk_property_float(ctx, label, VM_MIN, &handle->in0[i], VM_MAX, 1.f, 1.f); - nk_slider_float(ctx, VM_MIN, &handle->in0[i], VM_MAX, 1.f); - if(old_val != handle->in0[i]) - handle->writer(handle->controller, i + 2, sizeof(float), 0, &handle->in0[i]); - } - nk_tree_pop(ctx); - } + const float ratio [3] = {0.25f, 0.5f, 0.25f}; + nk_layout_row(ctx, NK_DYNAMIC, wh, 3, ratio); - nk_spacing(ctx, 1); - - if(nk_tree_push(ctx, NK_TREE_NODE, "Outputs", NK_MAXIMIZED)) + if(nk_group_begin(ctx, "Inputs", NK_WINDOW_TITLE | NK_WINDOW_BORDER)) + { + for(unsigned i = 0; i < CTRL_MAX; i++) { - for(unsigned i = 0; i < CTRL_MAX; i++) - { - char label [16]; - snprintf(label, 16, "Output %u", i); - nk_value_float(ctx, label, handle->out0[i]); - nk_slide_float(ctx, VM_MIN, handle->out0[i], VM_MAX, 1.f); - } - nk_tree_pop(ctx); + nk_layout_row_dynamic(ctx, dy*4, 1); + _draw_plot(ctx, handle->inp[i].vals, PLOT_MAX); + + nk_layout_row_dynamic(ctx, dy, 1); + const float old_val = handle->in0[i]; + nk_property_float(ctx, input_labels[i], VM_MIN, &handle->in0[i], VM_MAX, 1.f, 1.f); + if(old_val != handle->in0[i]) + handle->writer(handle->controller, i + 2, sizeof(float), 0, &handle->in0[i]); } nk_group_end(ctx); @@ -382,6 +399,20 @@ _expose(struct nk_context *ctx, struct nk_rect wbounds, void *data) nk_group_end(ctx); } + + if(nk_group_begin(ctx, "Outputs", NK_WINDOW_TITLE | NK_WINDOW_BORDER)) + { + for(unsigned i = 0; i < CTRL_MAX; i++) + { + nk_layout_row_dynamic(ctx, dy*4, 1); + _draw_plot(ctx, handle->outp[i].vals, PLOT_MAX); + + nk_layout_row_dynamic(ctx, dy, 1); + nk_labelf(ctx, NK_TEXT_LEFT, "Output %u: %+f", i, handle->out0[i]); + } + + nk_group_end(ctx); + } } nk_end(ctx); @@ -512,49 +543,79 @@ port_event(LV2UI_Handle instance, uint32_t index, uint32_t size, { if(protocol == handle->atom_eventTransfer) { - const LV2_Atom_Object *obj = buf; + const LV2_Atom *atom = buf; - atom_ser_t *ser = &handle->ser; - ser->offset = 0; - lv2_atom_forge_set_sink(&handle->forge, _sink, _deref, ser); + if(atom->type == handle->forge.Long) + { + const LV2_Atom_Long *off = buf; + + const int64_t dt = off->body - handle->off; + handle->off = off->body; - LV2_Atom_Forge_Ref ref; - if(props_advance(&handle->props, &handle->forge, 0, obj, &ref)) + const float rate = 48000.f / dt; //FIXME + const unsigned ntimes = 4; //FIXME + const unsigned window = ceilf(PLOT_MAX / rate / ntimes); + const unsigned remainder = PLOT_MAX - window; + + float mem [PLOT_MAX]; + bool needs_refresh = false; + + for(unsigned i = 0; i < CTRL_MAX; i++) + { + // inputs + { + memcpy(mem, &handle->inp[i].vals[window], sizeof(float)*remainder); + for(unsigned j = remainder; j < PLOT_MAX; j++) + mem[j] = handle->in0[i]; + + //FIXME can be made more efficient + if(memcmp(handle->inp[i].vals, mem, sizeof(float)*PLOT_MAX)) + needs_refresh = true; + + memcpy(handle->inp[i].vals, mem, sizeof(float)*PLOT_MAX); + } + + // outputs + { + memcpy(mem, &handle->outp[i].vals[window], sizeof(float)*remainder); + for(unsigned j = remainder; j < PLOT_MAX; j++) + mem[j] = handle->out0[i]; + + //FIXME can be made more efficient + if(memcmp(handle->outp[i].vals, mem, sizeof(float)*PLOT_MAX)) + needs_refresh = true; + + memcpy(handle->outp[i].vals, mem, sizeof(float)*PLOT_MAX); + } + } + + if(needs_refresh) + nk_pugl_post_redisplay(&handle->win); + } + else if(atom->type == handle->forge.Tuple) { - nk_pugl_post_redisplay(&handle->win); + const LV2_Atom_Int *idx = buf + 8; + const LV2_Atom_Float *val = buf + 8 + 16; + + if(idx->body < 10) + handle->in0[idx->body - 2] = val->body; + else + handle->out0[idx->body - 10] = val->body; } - } - } break; + else // !tuple + { + const LV2_Atom_Object *obj = buf; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - { - if(protocol == 0) - { - handle->in0[index - 2] = *(const float *)buf; - nk_pugl_post_redisplay(&handle->win); - } - } break; + atom_ser_t *ser = &handle->ser; + ser->offset = 0; + lv2_atom_forge_set_sink(&handle->forge, _sink, _deref, ser); - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - { - if(protocol == 0) - { - handle->out0[index - 10] = *(const float *)buf; - nk_pugl_post_redisplay(&handle->win); + LV2_Atom_Forge_Ref ref; + if(props_advance(&handle->props, &handle->forge, 0, obj, &ref)) + { + nk_pugl_post_redisplay(&handle->win); + } + } } } break; } |