aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHanspeter Portner <dev@open-music-kontrollers.ch>2017-03-23 17:34:21 +0100
committerHanspeter Portner <dev@open-music-kontrollers.ch>2017-03-23 17:34:21 +0100
commit02de8e72284619db9d9529380710458420518fa4 (patch)
treedef53302fe8f06b905d5aa0553607daf4409b828
parent3a9f0f747a5356b6ec304867db716f0e3ccb07ae (diff)
downloadvm.lv2-02de8e72284619db9d9529380710458420518fa4.tar.xz
prototype audio mixer widget.
-rw-r--r--VERSION2
-rw-r--r--vm.c12
-rw-r--r--vm.h23
-rw-r--r--vm.ttl40
-rw-r--r--vm_ui.c158
5 files changed, 182 insertions, 53 deletions
diff --git a/VERSION b/VERSION
index b2fae26..85de855 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.2889
+0.1.2891
diff --git a/vm.c b/vm.c
index ccd83a9..f4b3ea1 100644
--- a/vm.c
+++ b/vm.c
@@ -56,6 +56,8 @@ struct _plughandle_t {
LV2_Atom_Forge forge;
LV2_Atom_Forge_Ref ref;
+ vm_plug_enum_t vm_plug;
+
LV2_URID vm_graph;
LV2_Log_Log *log;
@@ -181,6 +183,8 @@ instantiate(const LV2_Descriptor* descriptor, num_t rate,
if(!handle)
return NULL;
+ handle->vm_plug = vm_plug_type(descriptor->URI);
+
for(unsigned i=0; features[i]; i++)
{
if(!strcmp(features[i]->URI, LV2_URID__map))
@@ -279,7 +283,9 @@ run_internal(plughandle_t *handle, uint32_t frames, bool notify,
{
for(unsigned i = 0; i < CTRL_MAX; i++)
{
- const float in1 = CLIP(VM_MIN, *in[i], VM_MAX);
+ const float in1 = (handle->vm_plug == VM_PLUG_AUDIO)
+ ? *in[i] // don't clip audio
+ : CLIP(VM_MIN, *in[i], VM_MAX);
if(handle->in0[i] != in1)
{
@@ -832,7 +838,9 @@ loop: {
for(unsigned i = 0; i < CTRL_MAX; i++)
{
- const float out1 = CLIP(VM_MIN, handle->out0[i], VM_MAX);
+ const float out1 = (handle->vm_plug == VM_PLUG_AUDIO)
+ ? handle->out0[i] // don't clip audio
+ :CLIP(VM_MIN, handle->out0[i], VM_MAX);
if(*out[i] != out1)
{
diff --git a/vm.h b/vm.h
index 0f5af61..24ecc54 100644
--- a/vm.h
+++ b/vm.h
@@ -59,6 +59,7 @@
#include <props.lv2/props.h>
+typedef enum _vm_plug_enum_t vm_plug_enum_t;
typedef enum _vm_status_t vm_status_t;
typedef enum _vm_opcode_enum_t vm_opcode_enum_t;
typedef enum _vm_command_enum_t vm_command_enum_t;
@@ -67,6 +68,13 @@ typedef struct _vm_api_def_t vm_api_def_t;
typedef struct _vm_api_impl_t vm_api_impl_t;
typedef struct _plugstate_t plugstate_t;
+enum _vm_plug_enum_t {
+ VM_PLUG_CONTROL = 0,
+ VM_PLUG_CV,
+ VM_PLUG_AUDIO,
+ VM_PLUG_ATOM
+};
+
enum _vm_status_t {
VM_STATUS_STATIC = (0 << 0),
VM_STATUS_HAS_TIME = (1 << 1),
@@ -797,6 +805,21 @@ static const vm_api_def_t vm_api_def [OP_MAX] = {
},
};
+static vm_plug_enum_t
+vm_plug_type(const char *plugin_uri)
+{
+ if(!strcmp(plugin_uri, VM_PREFIX"control"))
+ return VM_PLUG_CONTROL;
+ else if(!strcmp(plugin_uri, VM_PREFIX"cv"))
+ return VM_PLUG_CV;
+ else if(!strcmp(plugin_uri, VM_PREFIX"audio"))
+ return VM_PLUG_AUDIO;
+ else if(!strcmp(plugin_uri, VM_PREFIX"atom"))
+ return VM_PLUG_ATOM;
+
+ return VM_PLUG_CONTROL;
+}
+
static inline void
vm_api_init(vm_api_impl_t *impl, LV2_URID_Map *map)
{
diff --git a/vm.ttl b/vm.ttl
index ad6432e..05a6957 100644
--- a/vm.ttl
+++ b/vm.ttl
@@ -608,136 +608,96 @@ vm:audio
lv2:index 2 ;
lv2:symbol "audio_in_0" ;
lv2:name "Audio In 0" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
- lv2:default 0.0;
] , [
a lv2:InputPort,
lv2:AudioPort;
lv2:index 3 ;
lv2:symbol "audio_in_1" ;
lv2:name "Audio In 1" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
- lv2:default 0.0;
] , [
a lv2:InputPort,
lv2:AudioPort;
lv2:index 4 ;
lv2:symbol "audio_in_2" ;
lv2:name "Audio In 2" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
- lv2:default 0.0;
] , [
a lv2:InputPort,
lv2:AudioPort;
lv2:index 5 ;
lv2:symbol "audio_in_3" ;
lv2:name "Audio In 3" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
- lv2:default 0.0;
] , [
a lv2:InputPort,
lv2:AudioPort;
lv2:index 6 ;
lv2:symbol "audio_in_4" ;
lv2:name "Audio In 4" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
- lv2:default 0.0;
] , [
a lv2:InputPort,
lv2:AudioPort;
lv2:index 7 ;
lv2:symbol "audio_in_5" ;
lv2:name "Audio In 5" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
- lv2:default 0.0;
] , [
a lv2:InputPort,
lv2:AudioPort;
lv2:index 8 ;
lv2:symbol "audio_in_6" ;
lv2:name "Audio In 6" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
- lv2:default 0.0;
] , [
a lv2:InputPort,
lv2:AudioPort;
lv2:index 9 ;
lv2:symbol "audio_in_7" ;
lv2:name "Audio In 7" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
- lv2:default 0.0;
] , [
a lv2:OutputPort,
lv2:AudioPort;
lv2:index 10 ;
lv2:symbol "audio_out_0" ;
lv2:name "Audio Out 0" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
] , [
a lv2:OutputPort,
lv2:AudioPort;
lv2:index 11 ;
lv2:symbol "audio_out_1" ;
lv2:name "Audio Out 1" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
] , [
a lv2:OutputPort,
lv2:AudioPort;
lv2:index 12 ;
lv2:symbol "audio_out_2" ;
lv2:name "Audio Out 2" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
] , [
a lv2:OutputPort,
lv2:AudioPort;
lv2:index 13 ;
lv2:symbol "audio_out_3" ;
lv2:name "Audio Out 3" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
] , [
a lv2:OutputPort,
lv2:AudioPort;
lv2:index 14 ;
lv2:symbol "audio_out_4" ;
lv2:name "Audio Out 4" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
] , [
a lv2:OutputPort,
lv2:AudioPort;
lv2:index 15 ;
lv2:symbol "audio_out_5" ;
lv2:name "Audio Out 5" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
] , [
a lv2:OutputPort,
lv2:AudioPort;
lv2:index 16 ;
lv2:symbol "audio_out_6" ;
lv2:name "Audio Out 6" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
] , [
a lv2:OutputPort,
lv2:AudioPort;
lv2:index 17 ;
lv2:symbol "audio_out_7" ;
lv2:name "Audio Out 7" ;
- lv2:minimum -1.0;
- lv2:maximum 1.0;
] ;
#patch:writable
diff --git a/vm_ui.c b/vm_ui.c
index 49e0ef1..407eefd 100644
--- a/vm_ui.c
+++ b/vm_ui.c
@@ -59,6 +59,8 @@ struct _plughandle_t {
LV2_URID_Unmap *unmap;
LV2_Atom_Forge forge;
+ vm_plug_enum_t vm_plug;
+
LV2_URID atom_eventTransfer;
LV2_URID vm_graph;
@@ -84,6 +86,9 @@ struct _plughandle_t {
float in0 [CTRL_MAX];
float out0 [CTRL_MAX];
+ float in1 [CTRL_MAX];
+ float out1 [CTRL_MAX];
+
int64_t off;
plot_t inp [CTRL_MAX];
plot_t outp [CTRL_MAX];
@@ -252,6 +257,99 @@ _draw_plot(struct nk_context *ctx, const float *vals)
}
}
+static const int dBFS6_min = -54;
+static const int dBFS6_max = 6;
+static const int dBFS6_rng = dBFS6_max - dBFS6_min;
+static const int dBFS6_div = 2;
+
+static const float mx1 = (float)(dBFS6_rng - 2*dBFS6_max) / dBFS6_rng;
+static const float mx2 = (float)(2*dBFS6_max) / dBFS6_rng;
+
+static inline float
+dBFS6(float peak)
+{
+ const float d = dBFS6_max + 20.f * log10f(fabsf(peak) / dBFS6_div);
+ const float e = (d - dBFS6_min) / dBFS6_rng;
+ return NK_CLAMP(0.f, e, 1.f);
+}
+
+static inline void
+_draw_mixer(struct nk_context *ctx, float peak)
+{
+ peak = dBFS6(peak);
+
+ struct nk_rect bounds;
+ const enum nk_widget_layout_states states = nk_widget(&bounds, ctx);
+ if(states != NK_WIDGET_INVALID)
+ {
+ struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
+
+ const struct nk_color bg = ctx->style.property.normal.data.color;
+ nk_fill_rect(canvas, bounds, ctx->style.property.rounding, bg);
+ nk_stroke_rect(canvas, bounds, ctx->style.property.rounding, ctx->style.property.border, bg);
+
+ const struct nk_rect orig = bounds;
+ struct nk_rect outline;
+ const uint8_t alph = 0x7f;
+
+ // <= -6dBFS
+ {
+ const float dbfs = NK_MIN(peak, mx1);
+ const uint8_t dcol = 0xff * dbfs / mx1;
+ const struct nk_color left = nk_rgba(0x00, 0xff, 0xff, alph);
+ const struct nk_color bottom = left;
+ const struct nk_color right = nk_rgba(dcol, 0xff, 0xff-dcol, alph);
+ const struct nk_color top = right;
+
+ const float ox = ctx->style.font->height/2 + ctx->style.property.border + ctx->style.property.padding.x;
+ const float oy = ctx->style.property.border + ctx->style.property.padding.y;
+ bounds.x += ox;
+ bounds.y += oy;
+ bounds.w -= 2*ox;
+ bounds.h -= 2*oy;
+ outline = bounds;
+ bounds.w *= dbfs;
+
+ nk_fill_rect_multi_color(canvas, bounds, left, top, right, bottom);
+ }
+
+ // > 6dBFS
+ if(peak > mx1)
+ {
+ const float dbfs = peak - mx1;
+ const uint8_t dcol = 0xff * dbfs / mx2;
+ const struct nk_color left = nk_rgba(0xff, 0xff, 0x00, alph);
+ const struct nk_color bottom = left;
+ const struct nk_color right = nk_rgba(0xff, 0xff - dcol, 0x00, alph);
+ const struct nk_color top = right;
+
+ bounds = outline;
+ bounds.x += bounds.w * mx1;
+ bounds.w *= dbfs;
+ nk_fill_rect_multi_color(canvas, bounds, left, top, right, bottom);
+ }
+
+ // draw 6dBFS lines from -60 to +6
+ for(unsigned i = 0; i <= dBFS6_rng; i += dBFS6_max)
+ {
+ const bool is_zero = (i == dBFS6_rng - dBFS6_max);
+ const float dx = outline.w * i / dBFS6_rng;
+
+ const float x0 = outline.x + dx;
+ const float y0 = is_zero ? orig.y + 2.f : outline.y;
+
+ const float border = (is_zero ? 2.f : 1.f) * ctx->style.window.group_border;
+
+ const float x1 = x0;
+ const float y1 = is_zero ? orig.y + orig.h - 2.f : outline.y + outline.h;
+
+ nk_stroke_line(canvas, x0, y0, x1, y1, border, ctx->style.window.group_border_color);
+ }
+
+ nk_stroke_rect(canvas, outline, 0.f, ctx->style.window.group_border, ctx->style.window.group_border_color);
+ }
+}
+
static void
_expose(struct nk_context *ctx, struct nk_rect wbounds, void *data)
{
@@ -292,15 +390,25 @@ _expose(struct nk_context *ctx, struct nk_rect wbounds, void *data)
_draw_plot(ctx, handle->inp[i].vals);
nk_layout_row_dynamic(ctx, dy, 2);
- if(i == 0) // calculate only once
+ if( (handle->vm_plug == VM_PLUG_CONTROL)
+ || (handle->vm_plug == VM_PLUG_CV)
+ || (handle->vm_plug == VM_PLUG_ATOM) )
{
- stp = scl * VM_STP;
- fpp = scl * VM_RNG / nk_widget_width(ctx);
+ if(i == 0) // calculate only once
+ {
+ stp = scl * VM_STP;
+ fpp = scl * VM_RNG / nk_widget_width(ctx);
+ }
+ const float old_val = handle->in0[i];
+ nk_property_float(ctx, input_labels[i], VM_MIN, &handle->in0[i], VM_MAX, stp, fpp);
+ if(old_val != handle->in0[i])
+ handle->writer(handle->controller, i + 2, sizeof(float), 0, &handle->in0[i]);
+ }
+ else if(handle->vm_plug == VM_PLUG_AUDIO)
+ {
+ _draw_mixer(ctx, handle->in1[i]);
+ handle->in1[i] *= 0.9; //FIXME make dependent on ui:updateRate
}
- const float old_val = handle->in0[i];
- nk_property_float(ctx, input_labels[i], VM_MIN, &handle->in0[i], VM_MAX, stp, fpp);
- if(old_val != handle->in0[i])
- handle->writer(handle->controller, i + 2, sizeof(float), 0, &handle->in0[i]);
const int old_window = handle->inp[i].window;
nk_property_int(ctx, ms_label, 10, &handle->inp[i].window, 100000, 1, 1.f);
@@ -534,7 +642,17 @@ _expose(struct nk_context *ctx, struct nk_rect wbounds, void *data)
_draw_plot(ctx, handle->outp[i].vals);
nk_layout_row_dynamic(ctx, dy, 2);
- nk_labelf(ctx, NK_TEXT_LEFT, "Out %u: %+f", i, handle->out0[i]);
+ if( (handle->vm_plug == VM_PLUG_CONTROL)
+ || (handle->vm_plug == VM_PLUG_CV)
+ || (handle->vm_plug == VM_PLUG_ATOM) )
+ {
+ nk_labelf(ctx, NK_TEXT_LEFT, "Out %u: %+f", i, handle->out0[i]);
+ }
+ else if(handle->vm_plug == VM_PLUG_AUDIO)
+ {
+ _draw_mixer(ctx, handle->out1[i]);
+ handle->out1[i] *= 0.9; //FIXME make dependent on ui:updateRate
+ }
const int old_window = handle->outp[i].window;
nk_property_int(ctx, ms_label, 10, &handle->outp[i].window, 100000, 1, 1.f);
@@ -559,6 +677,8 @@ instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
if(!handle)
return NULL;
+ handle->vm_plug = vm_plug_type(plugin_uri);
+
void *parent = NULL;
LV2UI_Resize *host_resize = NULL;
LV2_Options_Option *opts = NULL;
@@ -776,9 +896,27 @@ port_event(LV2UI_Handle instance, uint32_t index, uint32_t size,
const LV2_Atom_Float *val = buf + 8 + 16;
if(idx->body < 10)
- handle->in0[idx->body - 2] = val->body;
+ {
+ const unsigned j = idx->body - 2;
+
+ if(handle->vm_plug == VM_PLUG_AUDIO)
+ {
+ handle->in0[j] = val->body;
+ if(val->body > handle->in1[j])
+ handle->in1[j] = val->body;
+ }
+ }
else
- handle->out0[idx->body - 10] = val->body;
+ {
+ const unsigned j = idx->body - 10;
+
+ if(handle->vm_plug == VM_PLUG_AUDIO)
+ {
+ handle->out0[j] = val->body;
+ if(val->body > handle->out1[j])
+ handle->out1[j] = val->body;
+ }
+ }
}
else // !tuple
{