1 /* 2 Copyright 2015 Nick Bailey 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <math.h> 9 #include "stegosaurus.h" 10 11 #include <cairo/cairo.h> 12 13 #include "lv2/lv2plug.in/ns/extensions/ui/ui.h" 14 #include "deliriumUI/deliriumUI.h" 15 16 #define stegosaurus_UI_URI "http://nickbailey.co.nr/plugins/stegosaurus#ui" 17 18 typedef struct { 19 PuglView* view; 20 LV2UI_Write_Function write; 21 LV2UI_Controller controller; 22 int width; 23 int height; 24 deliriumUI deliriumUI_window; 25 float brightness; 26 bool exit; 27 } stegosaurusUI; 28 29 static void 30 onReshape(PuglView* view, int width, int height) 31 { 32 33 stegosaurusUI* self = (stegosaurusUI*)puglGetHandle(view); 34 35 setDeliriumUICurrentWindowSize(&self->deliriumUI_window, width, height); 36 } 37 38 39 static void 40 onDisplay(PuglView* view) 41 { 42 stegosaurusUI* self = (stegosaurusUI*)puglGetHandle(view); 43 cairo_t* cr = puglGetContext(view); 44 45 displayAllDeliriumUIWidgets(&self->deliriumUI_window,cr); 46 } 47 48 static void 49 onKeyboard(PuglView* view, bool press, uint32_t key) 50 { 51 stegosaurusUI* self = (stegosaurusUI*)puglGetHandle(view); 52 cairo_t* cr = puglGetContext(view); 53 54 if (press) { 55 56 if (key==27) 57 { 58 self->exit = true; 59 } 60 61 62 if (key=='r') 63 { 64 displayAllDeliriumUIWidgets(&self->deliriumUI_window,cr); 65 } 66 67 fprintf(stderr, "Keyboard press %c\n", key); 68 } else { 69 fprintf(stderr, "Keyboard release %c\n", key); 70 } 71 } 72 73 static void 74 onMotion(PuglView* view, int x, int y) 75 { 76 stegosaurusUI* self = (stegosaurusUI*)puglGetHandle(view); 77 cairo_t* cr = puglGetContext(view); 78 79 // fprintf(stderr, "Motion: %d,%d\n", x, y); 80 isMouseOverDeliriumUIWidget(&self->deliriumUI_window, cr, x, y); 81 } 82 83 static void 84 onMouse(PuglView* view, int button, bool press, int x, int y) 85 { 86 if (press == true && button == 0 || button > 15) return; 87 88 stegosaurusUI* self = (stegosaurusUI*)puglGetHandle(view); 89 cairo_t* cr = puglGetContext(view); 90 91 self->deliriumUI_window.mouseButton[button] = press; 92 93 if (press == true && button == 3) 94 zeroValue(&self->deliriumUI_window, cr); 95 96 if (press == true && button == 1) 97 hasMouseClickedDeliriumUIWidget(&self->deliriumUI_window, x, y); 98 else 99 hasMouseClickedDeliriumUIWidget(&self->deliriumUI_window, -1,-1); 100 101 } 102 103 static void 104 onScroll(PuglView* view, int x, int y, float dx, float dy) 105 { 106 stegosaurusUI* self = (stegosaurusUI*)puglGetHandle(view); 107 cairo_t* cr = puglGetContext(view); 108 109 if (dy!=0) 110 { 111 112 if (dy == -1) 113 { 114 decValue(&self->deliriumUI_window, cr); 115 } 116 117 if (dy == 1) 118 { 119 incValue(&self->deliriumUI_window, cr); 120 } 121 } 122 } 123 124 125 static LV2UI_Handle 126 instantiate(const LV2UI_Descriptor* descriptor, 127 const char* plugin_uri, 128 const char* bundle_path, 129 LV2UI_Write_Function write_function, 130 LV2UI_Controller controller, 131 LV2UI_Widget* widget, 132 const LV2_Feature* const* features) 133 { 134 stegosaurusUI* self = (stegosaurusUI*)malloc(sizeof(stegosaurusUI)); 135 if (!self) { 136 return NULL; 137 } 138 139 self->write = write_function; 140 self->controller = controller; 141 self->width = 800; 142 self->height = 360; 143 self->exit = false; 144 145 self->deliriumUI_window.deliriumUIWidgets = NULL; 146 self->deliriumUI_window.numberOfUIWidgets = 1; 147 self->deliriumUI_window.currentWidgetNumber = -1; 148 149 for (int b=0; b<16; ++b) 150 { 151 self->deliriumUI_window.mouseButton[b] = 0; 152 self->deliriumUI_window.group_visible[b] = false; 153 self->deliriumUI_window.group_visible[b+16] = false; 154 } 155 156 setDeliriumUIGridSize(&self->deliriumUI_window, self->width, self->height, 16, 12); 157 158 159 // Get parent window and resize API from features 160 PuglNativeWindow parent = 0; 161 LV2UI_Resize* resize = NULL; 162 for (int i = 0; features && features[i]; ++i) { 163 printf("Feature %s\n", features[i]->URI ); 164 if (!strcmp(features[i]->URI, LV2_UI__parent)) { 165 parent = (PuglNativeWindow)features[i]->data; 166 } else if (!strcmp(features[i]->URI, LV2_UI__resize)) { 167 resize = (LV2UI_Resize*)features[i]->data; 168 } 169 } 170 171 if (!parent) { 172 fprintf(stderr, "error: stegosaurus_ui: No parent window provided.\n"); 173 free(self); 174 return NULL; 175 } 176 177 178 setControllerDiliriumUI(controller, write_function); 179 180 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Button, 5, 0,0,2,1,"KICK",-1); 181 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Button, 5, 2,0,2,1,"SNARE",-2); 182 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Button, 5, 4,0,2,1,"CLOSED HAT",-3); 183 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Button, 5, 6,0,2,1,"OPEN HAT",-4); 184 185 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Switch, 1, 0.5,3,1,2,"OSC 1",stegosaurus_KICK_OSC1_ACTIVE); 186 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 1, 1.5,2,1,4,"NOISE",stegosaurus_KICK_OSC1_NOISE); 187 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 1, 2.5,2,1,4,"PITCH",stegosaurus_KICK_OSC1_PITCH); 188 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 1, 4,2,3,3,"AMP",stegosaurus_KICK_OSC1_AMP_ATTACK); 189 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 1, 7.52,2,3,3,"PITCH",stegosaurus_KICK_OSC1_PITCH_ATTACK); 190 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 1, 11,2,1,4,"VOL",stegosaurus_KICK_OSC1_VOLUME); 191 192 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Switch, 1, 0.5,8,1,2,"OSC 2",stegosaurus_KICK_OSC2_ACTIVE); 193 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 1, 1.5,7,1,4,"NOISE",stegosaurus_KICK_OSC2_NOISE); 194 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 1, 2.5,7,1,4,"PITCH",stegosaurus_KICK_OSC2_PITCH); 195 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 1, 4,7,3,3,"AMP",stegosaurus_KICK_OSC2_AMP_ATTACK); 196 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 1, 7.52,7,3,3,"PITCH",stegosaurus_KICK_OSC2_PITCH_ATTACK); 197 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 1, 11,7,1,4,"VOL", stegosaurus_KICK_OSC2_VOLUME); 198 199 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Switch, 2, 0.5,3,1,2,"OSC 1",stegosaurus_SNARE_OSC1_ACTIVE); 200 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 2, 1.5,2,1,4,"NOISE",stegosaurus_SNARE_OSC1_NOISE); 201 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 2, 2.5,2,1,4,"PITCH",stegosaurus_SNARE_OSC1_PITCH); 202 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 2, 4,2,3,3,"AMP",stegosaurus_SNARE_OSC1_AMP_ATTACK); 203 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 2, 7.52,2,3,3,"PITCH",stegosaurus_SNARE_OSC1_PITCH_ATTACK); 204 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 2, 11,2,1,4,"VOL",stegosaurus_SNARE_OSC1_VOLUME); 205 206 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Switch, 2, 0.5,8,1,2,"OSC 2",stegosaurus_SNARE_OSC2_ACTIVE); 207 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 2, 1.5,7,1,4,"NOISE",stegosaurus_SNARE_OSC2_NOISE); 208 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 2, 2.5,7,1,4,"PITCH",stegosaurus_SNARE_OSC2_PITCH); 209 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 2, 4,7,3,3,"AMP",stegosaurus_SNARE_OSC2_AMP_ATTACK); 210 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 2, 7.52,7,3,3,"PITCH",stegosaurus_SNARE_OSC2_PITCH_ATTACK); 211 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 2, 11,7,1,4,"VOL", stegosaurus_SNARE_OSC2_VOLUME); 212 213 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Switch, 3, 0.5,3,1,2,"OSC 1",stegosaurus_CLHAT_OSC1_ACTIVE); 214 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 3, 1.5,2,1,4,"NOISE",stegosaurus_CLHAT_OSC1_NOISE); 215 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 3, 2.5,2,1,4,"PITCH",stegosaurus_CLHAT_OSC1_PITCH); 216 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 3, 4,2,3,3,"AMP",stegosaurus_CLHAT_OSC1_AMP_ATTACK); 217 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 3, 7.52,2,3,3,"PITCH",stegosaurus_CLHAT_OSC1_PITCH_ATTACK); 218 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 3, 11,2,1,4,"VOL",stegosaurus_CLHAT_OSC1_VOLUME); 219 220 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Switch, 3, 0.5,8,1,2,"OSC 2",stegosaurus_CLHAT_OSC2_ACTIVE); 221 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 3, 1.5,7,1,4,"NOISE",stegosaurus_CLHAT_OSC2_NOISE); 222 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 3, 2.5,7,1,4,"PITCH",stegosaurus_CLHAT_OSC2_PITCH); 223 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 3, 4,7,3,3,"AMP",stegosaurus_CLHAT_OSC2_AMP_ATTACK); 224 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 3, 7.52,7,3,3,"PITCH",stegosaurus_CLHAT_OSC2_PITCH_ATTACK); 225 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 3, 11,7,1,4,"VOL", stegosaurus_CLHAT_OSC2_VOLUME); 226 227 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Switch, 4, 0.5,3,1,2,"OSC 1",stegosaurus_OPHAT_OSC1_ACTIVE); 228 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 4, 1.5,2,1,4,"NOISE",stegosaurus_OPHAT_OSC1_NOISE); 229 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 4, 2.5,2,1,4,"PITCH",stegosaurus_OPHAT_OSC1_PITCH); 230 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 4, 4,2,3,3,"AMP",stegosaurus_OPHAT_OSC1_AMP_ATTACK); 231 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 4, 7.52,2,3,3,"PITCH",stegosaurus_OPHAT_OSC1_PITCH_ATTACK); 232 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 4, 11,2,1,4,"VOL",stegosaurus_OPHAT_OSC1_VOLUME); 233 234 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Switch, 4, 0.5,8,1,2,"OSC 2",stegosaurus_OPHAT_OSC2_ACTIVE); 235 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 4, 1.5,7,1,4,"NOISE",stegosaurus_OPHAT_OSC2_NOISE); 236 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 4, 2.5,7,1,4,"PITCH",stegosaurus_OPHAT_OSC2_PITCH); 237 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 4, 4,7,3,3,"AMP",stegosaurus_OPHAT_OSC2_AMP_ATTACK); 238 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_ADSR, 4, 7.52,7,3,3,"PITCH",stegosaurus_OPHAT_OSC2_PITCH_ATTACK); 239 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Fader, 4, 11,7,1,4,"VOL", stegosaurus_OPHAT_OSC2_VOLUME); 240 241 addDeliriumUIWidget(&self->deliriumUI_window, deliriumUI_Knob, 5, 13.5,6,2,4,"VOLUME",stegosaurus_VOLUME); 242 243 self->deliriumUI_window.group_visible[1] = true; 244 self->deliriumUI_window.group_visible[2] = false; 245 self->deliriumUI_window.group_visible[3] = false; 246 self->deliriumUI_window.group_visible[4] = false; 247 self->deliriumUI_window.group_visible[5] = true; 248 249 // Set up pugl window 250 251 self->view = puglInit(NULL, NULL); 252 puglInitResizable(self->view, false); 253 puglInitWindowParent(self->view, parent); 254 puglInitWindowSize(self->view, 800,360); 255 puglInitContextType(self->view, PUGL_CAIRO); 256 puglIgnoreKeyRepeat(self->view, false); 257 258 puglSetDisplayFunc(self->view, onDisplay); 259 puglSetReshapeFunc(self->view, onReshape); 260 puglSetKeyboardFunc(self->view, onKeyboard); 261 puglSetMotionFunc(self->view, onMotion); 262 puglSetMouseFunc(self->view, onMouse); 263 puglSetScrollFunc(self->view, onScroll); 264 265 puglCreateWindow(self->view, "stegosaurus"); 266 puglSetHandle(self->view, self); 267 puglShowWindow(self->view); 268 269 if (resize) { 270 resize->ui_resize(resize->handle, self->width, self->height); 271 } 272 273 *widget = (void*)puglGetNativeWindow(self->view); 274 return self; 275 } 276 277 static int 278 idle(LV2UI_Handle handle) 279 { 280 stegosaurusUI* self = (stegosaurusUI*)handle; 281 282 // Silly pulsing animation to check that idle handler is working 283 self->brightness = fmod(self->brightness + 0.01, 1.0); 284 puglPostRedisplay(self->view); 285 puglProcessEvents(self->view); 286 287 return 0; 288 } 289 290 static void 291 cleanup(LV2UI_Handle handle) 292 { 293 294 stegosaurusUI* self = (stegosaurusUI*)handle; 295 self->exit = true; 296 297 fprintf(stderr, "\nstegosaurus shutting down........\n"); 298 299 puglDestroy(self->view); 300 free(self); 301 302 } 303 304 static void 305 port_event(LV2UI_Handle handle, 306 uint32_t port_index, 307 uint32_t buffer_size, 308 uint32_t format, 309 const void* buffer) 310 { 311 stegosaurusUI* self = (stegosaurusUI*)handle; 312 cairo_t* cr = puglGetContext(self->view); 313 float value = *(float*)buffer; 314 315 setValue(&self->deliriumUI_window, cr, port_index, value); 316 317 318 } 319 320 static const LV2UI_Idle_Interface idle_iface = { idle }; 321 322 static const void* 323 extension_data(const char* uri) 324 { 325 if (!strcmp(uri, LV2_UI__idleInterface)) { 326 return &idle_iface; 327 } 328 return NULL; 329 } 330 331 static const LV2UI_Descriptor descriptor = { 332 stegosaurus_UI_URI, 333 instantiate, 334 cleanup, 335 port_event, 336 extension_data 337 }; 338 339 LV2_SYMBOL_EXPORT 340 const LV2UI_Descriptor* 341 lv2ui_descriptor(uint32_t index) 342 { 343 switch (index) { 344 case 0: 345 return &descriptor; 346 default: 347 return NULL; 348 } 349 } 350 351 352 353 354 355 356 357 358