297 lines
6.9 KiB
C++
297 lines
6.9 KiB
C++
/*
|
|
Copyright 2013 Peter Nelson
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
#define _BSD_SOURCE 1
|
|
#include <unistd.h> /* for usleep */
|
|
|
|
#include <pthread.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <lv2.h>
|
|
#include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
|
|
#include <pugl/pugl.h>
|
|
#include <limits.h>
|
|
#include "../pui/pui.h"
|
|
#include "ptap.h"
|
|
|
|
/*struct PTapUI : PTextures {
|
|
PuglView *view;
|
|
pthread_t thread;
|
|
LV2UI_Write_Function write;
|
|
LV2UI_Controller controller;
|
|
int width;
|
|
int height;
|
|
bool exit;
|
|
|
|
int mx;
|
|
int my;
|
|
int mb;
|
|
int mm;
|
|
Widget *active;
|
|
|
|
Container *widget;
|
|
|
|
void InitWidgets();
|
|
};*/
|
|
|
|
struct PTapUI : PUi {
|
|
pthread_t thread;
|
|
LV2UI_Write_Function write;
|
|
LV2UI_Controller controller;
|
|
int width;
|
|
int height;
|
|
bool exit;
|
|
|
|
virtual ~PTapUI() {}
|
|
|
|
void InitWidgets();
|
|
|
|
/* virtual */ void ParameterChanged(const Widget *w);
|
|
};
|
|
|
|
void PTapUI::InitWidgets()
|
|
{
|
|
char tmp[128];
|
|
|
|
scale = 1.0f;
|
|
|
|
widget = new Container();
|
|
widget->back = 1;
|
|
widget->colour = Colour(1, 1, 1, 1);
|
|
widget->w = this->width * scale;
|
|
widget->h = this->height * scale;
|
|
|
|
int padding = 4;
|
|
|
|
int cols = 2;
|
|
int rows = (NUM_TAPS + NUM_CHANNELS + cols - 1) / cols;
|
|
|
|
int c_w = (widget->w - padding * cols - padding) / cols;
|
|
int c_h = (widget->h - 25 - padding * rows - padding) / rows;
|
|
|
|
Container *t = new Container();
|
|
t->colour = Colour(0, 0, 0, .5f);
|
|
t->x = 0;
|
|
t->y = 0;
|
|
t->w = widget->w;
|
|
t->h = 25;
|
|
this->widget->Pack(t);
|
|
|
|
for (int i = 0; i < NUM_TAPS + NUM_CHANNELS; i++) {
|
|
Container *c = new VBox();
|
|
if (i < NUM_TAPS) c->frame = Colour(0, 0, 0, .15f);
|
|
c->x = (i & 1) * (c_w + padding) + padding;
|
|
c->y = (i >> 1) * (c_h + padding) + padding + 25;
|
|
c->w = c_w;
|
|
c->h = c_h;
|
|
c->padding = padding;
|
|
|
|
Container *c1 = new Container();
|
|
c1->h = 16;
|
|
c->Pack(c1);
|
|
|
|
Container *c_strip = new HBox();
|
|
c_strip->h = -1;
|
|
c_strip->padding = padding;
|
|
c->Pack(c_strip);
|
|
|
|
Container *c_taps = new HBox();
|
|
if (i >= NUM_TAPS) c_taps->colour = Colour(1, 1, 1, 0.15f);
|
|
c_strip->Pack(c_taps);
|
|
|
|
if (i < NUM_TAPS) {
|
|
snprintf(tmp, sizeof tmp, "Tap %d", i + 1);
|
|
} else {
|
|
strncpy(tmp, i == NUM_TAPS ? "Left Out" : "Right Out", sizeof tmp);
|
|
}
|
|
|
|
for (int j = 0; j < NUM_TAPS; j++) {
|
|
Slider *slider = new VSlider();
|
|
strncpy(slider->group, tmp, sizeof slider->group);
|
|
snprintf(slider->label, sizeof slider->label, "%d", j + 1);
|
|
if (i == j) {
|
|
slider->colour = Colour(.5f, .7f, 1, 1);
|
|
} else {
|
|
slider->colour = Colour(.6f, .6f, .6f, 1);
|
|
}
|
|
slider->min = -1.f;
|
|
slider->max = 1.f;
|
|
slider->port = TAP_MATRIX + i * NUM_GAINS + j;
|
|
c_taps->Pack(slider);
|
|
}
|
|
|
|
Container *c_ins = new HBox();
|
|
if (i >= NUM_TAPS) c_ins->colour = Colour(1, 1, 1, 0.15f);
|
|
c_strip->Pack(c_ins);
|
|
|
|
for (int j = 0; j < NUM_CHANNELS; j++) {
|
|
Slider *slider = new VSlider();
|
|
strncpy(slider->group, tmp, sizeof slider->group);
|
|
strncpy(slider->label, j == 0 ? "Left" : "Right", sizeof slider->label);
|
|
slider->min = -1.f;
|
|
slider->max = 1.f;
|
|
slider->port = TAP_MATRIX + i * NUM_GAINS + NUM_TAPS + j;
|
|
c_ins->Pack(slider);
|
|
}
|
|
|
|
Slider *gain = new VSlider(i >= NUM_TAPS);
|
|
strncpy(gain->group, tmp, sizeof gain->group);
|
|
strncpy(gain->label, "Gain", sizeof gain->label);
|
|
gain->colour = Colour(1, .2f, .2f, 1);
|
|
gain->min = -1.f;
|
|
gain->max = 1.f;
|
|
gain->port = TAP_GAINS + i;
|
|
c_strip->Pack(gain);
|
|
|
|
if (i < NUM_TAPS) {
|
|
Knob *delay = new Knob();
|
|
strncpy(delay->group, tmp, sizeof delay->group);
|
|
strncpy(delay->label, "Delay", sizeof delay->label);
|
|
delay->w = -1;
|
|
delay->min = 0.f;
|
|
delay->max = 10.f;
|
|
delay->port = TAP_DELAYS + i;
|
|
c_strip->Pack(delay);
|
|
}
|
|
|
|
this->widget->Pack(c);
|
|
}
|
|
|
|
tooltip = new Label();
|
|
tooltip->x = widget->w * 0.5f;
|
|
tooltip->y = 10;
|
|
tooltip->colour = Colour(1, 1, 1, 1);
|
|
tooltip->SetLabel("INIT");
|
|
this->widget->Pack(tooltip);
|
|
}
|
|
|
|
static void *ui_thread(void *ptr)
|
|
{
|
|
PTapUI *pui = (PTapUI *)ptr;
|
|
while (!pui->exit) {
|
|
usleep(1000000 / 25);
|
|
puglProcessEvents(pui->view);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void PTapUI::ParameterChanged(const Widget *w)
|
|
{
|
|
if (w->port == UINT_MAX) return;
|
|
|
|
this->write(this->controller, w->port, sizeof w->value, 0, &w->value);
|
|
|
|
char tmp[64];
|
|
snprintf(tmp, sizeof tmp, "(%s) %s: %0.4f", w->group, w->label, w->value);
|
|
tooltip->SetLabel(tmp);
|
|
}
|
|
|
|
static LV2UI_Handle ptapui_instantiate(
|
|
const LV2UI_Descriptor *descriptor,
|
|
const char *plugin_uri,
|
|
const char *bundle_path,
|
|
LV2UI_Write_Function write_function,
|
|
LV2UI_Controller controller,
|
|
LV2UI_Widget *widget,
|
|
const LV2_Feature *const *host_features)
|
|
{
|
|
PuglNativeWindow parent = 0;
|
|
LV2UI_Resize *resize = NULL;
|
|
for (; host_features && *host_features; host_features++) {
|
|
if (!strcmp((*host_features)->URI, LV2_UI__parent)) {
|
|
parent = (PuglNativeWindow)(*host_features)->data;
|
|
} else if (!strcmp((*host_features)->URI, LV2_UI__resize)) {
|
|
resize = (LV2UI_Resize *)(*host_features)->data;
|
|
}
|
|
}
|
|
|
|
if (!parent) {
|
|
fprintf(stderr, "error: ptapui: No parent window provided.\n");
|
|
return NULL;
|
|
}
|
|
|
|
PTapUI *pui = new PTapUI();
|
|
pui->write = write_function;
|
|
pui->controller = controller;
|
|
pui->width = 250 + 50 * (NUM_TAPS + NUM_CHANNELS + 1);
|
|
pui->height = 660;
|
|
pui->exit = false;
|
|
|
|
pui->InitWidgets();
|
|
|
|
pui->view = puglCreate(parent, "PTap", pui->width, pui->height, true);
|
|
puglSetHandle(pui->view, pui);
|
|
|
|
pui->SetFunc();
|
|
|
|
if (resize) {
|
|
resize->ui_resize(resize->handle, pui->width, pui->height);
|
|
}
|
|
|
|
pthread_create(&pui->thread, NULL, ui_thread, pui);
|
|
|
|
*widget = (void*)puglGetNativeWindow(pui->view);
|
|
return pui;
|
|
}
|
|
|
|
static void ptapui_cleanup(LV2UI_Handle ui)
|
|
{
|
|
PTapUI *pui = (PTapUI *)ui;
|
|
pui->exit = true;
|
|
pthread_join(pui->thread, NULL);
|
|
puglDestroy(pui->view);
|
|
delete pui;
|
|
}
|
|
|
|
static void ptapui_port_event(
|
|
LV2UI_Handle ui,
|
|
uint32_t port_index,
|
|
uint32_t buffer_size,
|
|
uint32_t format,
|
|
const void *buffer)
|
|
{
|
|
PUi *pui = (PUi *)ui;
|
|
Widget *w = pui->widget->GetWidget(port_index);
|
|
if (!w) return;
|
|
|
|
w->SetValue(*((float *)buffer));
|
|
pui->Repaint();
|
|
}
|
|
|
|
static const void *ptapui_extension_data(const char *uri)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static const LV2UI_Descriptor s_lv2uidescriptor =
|
|
{
|
|
PTAP_URI "#X11UI",
|
|
&ptapui_instantiate,
|
|
&ptapui_cleanup,
|
|
&ptapui_port_event,
|
|
&ptapui_extension_data,
|
|
};
|
|
|
|
const LV2UI_Descriptor *lv2ui_descriptor(uint32_t index)
|
|
{
|
|
if (index == 0) {
|
|
return &s_lv2uidescriptor;
|
|
}
|
|
|
|
return NULL;
|
|
}
|