Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / server / plugins / UIUGens.cpp
blob42deacb678a682081b8f6d70beaf316653979745
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #ifdef __APPLE__
23 #include <Carbon/Carbon.h>
24 #include <unistd.h>
25 #else
26 # ifndef _WIN32
27 # include <time.h>
28 # include <X11/Intrinsic.h>
29 # else
30 #include <windows.h>
31 # endif
32 #endif
34 #include "SC_PlugIn.h"
36 static InterfaceTable *ft;
38 struct KeyboardUGenGlobalState {
39 #ifdef __APPLE__
40 // uint8 keys[16];
41 KeyMap keys;
42 #else
43 uint8 keys[32];
44 #endif
45 } gKeyStateGlobals;
47 struct KeyState : public Unit
49 float m_y1, m_b1, m_lag;
53 struct MouseUGenGlobalState {
54 float mouseX, mouseY;
55 bool mouseButton;
56 } gMouseUGenGlobals;
58 struct MouseInputUGen : public Unit
60 float m_y1, m_b1, m_lag;
64 //////////////////////////////////////////////////////////////////////////////////////////////////
66 #ifdef __APPLE__
68 void* gstate_update_func(void* arg)
70 #if (__x86_64__)
71 CGDirectDisplayID display = kCGDirectMainDisplay; // to grab the main display ID
72 CGRect bounds = CGDisplayBounds(display);
73 float rscreenWidth = 1. / bounds.size.width;
74 float rscreenHeight = 1. / bounds.size.height;
75 #else
76 RgnHandle rgn = GetGrayRgn();
77 Rect screenBounds;
78 GetRegionBounds(rgn, &screenBounds);
79 float rscreenWidth = 1. / (screenBounds.right - screenBounds.left);
80 float rscreenHeight = 1. / (screenBounds.bottom - screenBounds.top);
81 #endif
82 for (;;) {
83 GetKeys(gKeyStateGlobals.keys);
85 #if (__x86_64__)
86 HIPoint point;
87 HICoordinateSpace space = 2;
88 HIGetMousePosition(space, NULL, &point);
90 gMouseUGenGlobals.mouseX = point.x * rscreenWidth; //(float)p.h * rscreenWidth;
91 gMouseUGenGlobals.mouseY = point.y * rscreenHeight; //(float)p.v * rscreenHeight;
92 gMouseUGenGlobals.mouseButton = GetCurrentButtonState();
93 #else
94 Point p;
95 GetGlobalMouse(&p);
96 gMouseUGenGlobals.mouseX = (float)p.h * rscreenWidth;
97 gMouseUGenGlobals.mouseY = (float)p.v * rscreenHeight;
98 gMouseUGenGlobals.mouseButton = Button();
99 #endif
100 usleep(17000);
103 return 0;
106 #elif defined(_WIN32)
108 void* gstate_update_func(void* arg)
110 POINT p;
111 int mButton;
113 if(GetSystemMetrics(SM_SWAPBUTTON))
114 mButton = VK_RBUTTON; // if swapped
115 else
116 mButton = VK_LBUTTON; // not swapped (normal)
118 int screenWidth = GetSystemMetrics( SM_CXSCREEN );
119 int screenHeight = GetSystemMetrics( SM_CYSCREEN );
120 // default: SM_CX/CYSCREEN gets the size of a primary screen.
121 // lines uncommented below are just for a specially need on multi-display.
122 //int screenWidth = GetSystemMetrics( SM_CXVIRTUALSCREEN );
123 //int screenHeight = GetSystemMetrics( SM_CYVIRTUALSCREEN );
124 float r_screenWidth = 1.f / (float)(screenWidth -1);
125 float r_screenHeight = 1.f / (float)(screenHeight -1);
128 for(;;) {
129 // "KeyState" is disabled for now, on Windows...
130 //GetKey((long*)gstate->keys);
132 GetCursorPos(&p);
133 gMouseUGenGlobals.mouseX = (float)p.x * r_screenWidth;
134 gMouseUGenGlobals.mouseY = 1.f - (float)p.y * r_screenHeight;
135 gMouseUGenGlobals.mouseButton = (GetKeyState(mButton) < 0);
136 ::Sleep(17); // 17msec.
138 return 0;
141 # else
142 static Display * d = 0;
143 void* gstate_update_func(void* arg)
145 Window r;
146 struct timespec requested_time , remaining_time;
148 requested_time.tv_sec = 0;
149 requested_time.tv_nsec = 17000 * 1000;
151 d = XOpenDisplay ( NULL );
152 if (!d) return 0;
154 Window rep_root, rep_child;
155 XWindowAttributes attributes;
156 int rep_rootx, rep_rooty ;
157 unsigned int rep_mask;
158 int dx, dy;
159 float r_width;
160 float r_height;
162 r = DefaultRootWindow ( d );
163 XGetWindowAttributes ( d, r, &attributes );
164 r_width = 1.0 / (float)attributes.width;
165 r_height = 1.0 / (float)attributes.height;
167 for (;;) {
168 XQueryKeymap ( d , (char *) (gKeyStateGlobals.keys) );
169 XQueryPointer ( d, r,
170 &rep_root, &rep_child,
171 &rep_rootx, &rep_rooty,
172 &dx, &dy,
173 &rep_mask);
175 gMouseUGenGlobals.mouseX = (float)dx * r_width;
176 gMouseUGenGlobals.mouseY = 1.f - ( (float)dy * r_height );
178 gMouseUGenGlobals.mouseButton = (bool) ( rep_mask & Button1Mask );
180 nanosleep ( &requested_time , &remaining_time );
183 return 0;
185 #endif
187 //////////////////////////////////////////////////////////////////////////////////////////////////
189 void KeyState_next(KeyState *unit, int inNumSamples)
191 // minval, maxval, warp, lag
192 uint8 *keys = (uint8*)gKeyStateGlobals.keys;
193 int keynum = (int)ZIN0(0);
194 #ifdef __APPLE__
195 int byte = (keynum >> 3) & 15;
196 #else
197 int byte = (keynum >> 3) & 31;
198 #endif
199 int bit = keynum & 7;
200 int val = keys[byte] & (1 << bit);
202 float minval = ZIN0(1);
203 float maxval = ZIN0(2);
204 float lag = ZIN0(3);
206 float y1 = unit->m_y1;
207 float b1 = unit->m_b1;
209 if (lag != unit->m_lag) {
210 unit->m_b1 = lag == 0.f ? 0.f : exp(log001 / (lag * unit->mRate->mSampleRate));
211 unit->m_lag = lag;
213 float y0 = val ? maxval : minval;
214 ZOUT0(0) = y1 = y0 + b1 * (y1 - y0);
215 unit->m_y1 = zapgremlins(y1);
218 void KeyState_Ctor(KeyState *unit)
220 SETCALC(KeyState_next);
221 unit->m_b1 = 0.f;
222 unit->m_lag = 0.f;
223 KeyState_next(unit, 1);
226 //////////////////////////////////////////////////////////////////////////////////////////////////
228 void MouseX_next(MouseInputUGen *unit, int inNumSamples)
230 // minval, maxval, warp, lag
232 float minval = ZIN0(0);
233 float maxval = ZIN0(1);
234 float warp = ZIN0(2);
235 float lag = ZIN0(3);
237 float y1 = unit->m_y1;
238 float b1 = unit->m_b1;
240 if (lag != unit->m_lag) {
241 unit->m_b1 = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate));
242 unit->m_lag = lag;
244 float y0 = gMouseUGenGlobals.mouseX;
245 if (warp == 0.0) {
246 y0 = (maxval - minval) * y0 + minval;
247 } else {
248 y0 = pow(maxval/minval, y0) * minval;
250 ZOUT0(0) = y1 = y0 + b1 * (y1 - y0);
251 unit->m_y1 = zapgremlins(y1);
254 void MouseX_Ctor(MouseInputUGen *unit)
256 SETCALC(MouseX_next);
257 unit->m_b1 = 0.f;
258 unit->m_lag = 0.f;
259 MouseX_next(unit, 1);
263 void MouseY_next(MouseInputUGen *unit, int inNumSamples)
265 // minval, maxval, warp, lag
267 float minval = ZIN0(0);
268 float maxval = ZIN0(1);
269 float warp = ZIN0(2);
270 float lag = ZIN0(3);
272 float y1 = unit->m_y1;
273 float b1 = unit->m_b1;
275 if (lag != unit->m_lag) {
276 unit->m_b1 = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate));
277 unit->m_lag = lag;
279 float y0 = gMouseUGenGlobals.mouseY;
280 if (warp == 0.0) {
281 y0 = (maxval - minval) * y0 + minval;
282 } else {
283 y0 = pow(maxval/minval, y0) * minval;
285 ZOUT0(0) = y1 = y0 + b1 * (y1 - y0);
286 unit->m_y1 = zapgremlins(y1);
289 void MouseY_Ctor(MouseInputUGen *unit)
291 SETCALC(MouseY_next);
292 unit->m_b1 = 0.f;
293 unit->m_lag = 0.f;
294 MouseY_next(unit, 1);
298 void MouseButton_next(MouseInputUGen *unit, int inNumSamples)
300 // minval, maxval, warp, lag
302 float minval = ZIN0(0);
303 float maxval = ZIN0(1);
304 float lag = ZIN0(2);
306 float y1 = unit->m_y1;
307 float b1 = unit->m_b1;
309 if (lag != unit->m_lag) {
310 unit->m_b1 = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate));
311 unit->m_lag = lag;
313 float y0 = gMouseUGenGlobals.mouseButton ? maxval : minval;
314 ZOUT0(0) = y1 = y0 + b1 * (y1 - y0);
315 unit->m_y1 = zapgremlins(y1);
318 void MouseButton_Ctor(MouseInputUGen *unit)
320 SETCALC(MouseButton_next);
321 unit->m_b1 = 0.f;
322 unit->m_lag = 0.f;
323 MouseButton_next(unit, 1);
326 //////////////////////////////////////////////////////////////////////////////////////////////////
327 //////////////////////////////////////////////////////////////////////////////////////////////////
328 //////////////////////////////////////////////////////////////////////////////////////////////////
330 // example of implementing a plug in command with async execution.
332 struct MyPluginData // data for the global instance of the plugin
334 float a, b;
337 struct MyCmdData // data for each command
339 MyPluginData* myPlugin;
340 float x, y;
341 char *name;
344 MyPluginData gMyPlugin; // global
346 bool cmdStage2(World* world, void* inUserData)
348 // user data is the command.
349 MyCmdData* myCmdData = (MyCmdData*)inUserData;
351 // just print out the values
352 Print("cmdStage2 a %g b %g x %g y %g name %s\n",
353 myCmdData->myPlugin->a, myCmdData->myPlugin->b,
354 myCmdData->x, myCmdData->y,
355 myCmdData->name);
357 return true;
360 bool cmdStage3(World* world, void* inUserData)
362 // user data is the command.
363 MyCmdData* myCmdData = (MyCmdData*)inUserData;
365 // just print out the values
366 Print("cmdStage3 a %g b %g x %g y %g name %s\n",
367 myCmdData->myPlugin->a, myCmdData->myPlugin->b,
368 myCmdData->x, myCmdData->y,
369 myCmdData->name);
371 // scsynth will perform completion message after this returns
372 return true;
375 bool cmdStage4(World* world, void* inUserData)
377 // user data is the command.
378 MyCmdData* myCmdData = (MyCmdData*)inUserData;
380 // just print out the values
381 Print("cmdStage4 a %g b %g x %g y %g name %s\n",
382 myCmdData->myPlugin->a, myCmdData->myPlugin->b,
383 myCmdData->x, myCmdData->y,
384 myCmdData->name);
386 // scsynth will send /done after this returns
387 return true;
390 void cmdCleanup(World* world, void* inUserData)
392 // user data is the command.
393 MyCmdData* myCmdData = (MyCmdData*)inUserData;
395 Print("cmdCleanup a %g b %g x %g y %g name %s\n",
396 myCmdData->myPlugin->a, myCmdData->myPlugin->b,
397 myCmdData->x, myCmdData->y,
398 myCmdData->name);
400 RTFree(world, myCmdData->name); // free the string
401 RTFree(world, myCmdData); // free command data
402 // scsynth will delete the completion message for you.
405 void cmdDemoFunc(World *inWorld, void* inUserData, struct sc_msg_iter *args, void *replyAddr)
407 Print("->cmdDemoFunc %p\n", inUserData);
409 // user data is the plug-in's user data.
410 MyPluginData* thePlugInData = (MyPluginData*)inUserData;
412 // allocate command data, free it in cmdCleanup.
413 MyCmdData* myCmdData = (MyCmdData*)RTAlloc(inWorld, sizeof(MyCmdData));
414 myCmdData->myPlugin = thePlugInData;
416 // ..get data from args..
417 myCmdData->x = 0.;
418 myCmdData->y = 0.;
419 myCmdData->name = 0;
421 // float arguments
422 myCmdData->x = args->getf();
423 myCmdData->y = args->getf();
425 // how to pass a string argument:
426 const char *name = args->gets(); // get the string argument
427 if (name) {
428 myCmdData->name = (char*)RTAlloc(inWorld, strlen(name)+1); // allocate space, free it in cmdCleanup.
429 strcpy(myCmdData->name, name); // copy the string
432 // how to pass a completion message
433 int msgSize = args->getbsize();
434 char* msgData = 0;
435 if (msgSize) {
436 // allocate space for completion message
437 // scsynth will delete the completion message for you.
438 msgData = (char*)RTAlloc(inWorld, msgSize);
439 args->getb(msgData, msgSize); // copy completion message.
442 DoAsynchronousCommand(inWorld, replyAddr, "cmdDemoFunc", (void*)myCmdData,
443 (AsyncStageFn)cmdStage2,
444 (AsyncStageFn)cmdStage3,
445 (AsyncStageFn)cmdStage4,
446 cmdCleanup,
447 msgSize, msgData);
449 Print("<-cmdDemoFunc\n");
453 * to test the above, send the server these commands:
456 * SynthDef(\sine, { Out.ar(0, SinOsc.ar(800,0,0.2)) }).load(s);
457 * s.sendMsg(\cmd, \pluginCmdDemo, 7, 9, \mno, [\s_new, \sine, 900, 0, 0]);
458 * s.sendMsg(\n_free, 900);
459 * s.sendMsg(\cmd, \pluginCmdDemo, 7, 9, \mno);
460 * s.sendMsg(\cmd, \pluginCmdDemo, 7, 9);
461 * s.sendMsg(\cmd, \pluginCmdDemo, 7);
462 * s.sendMsg(\cmd, \pluginCmdDemo);
468 PluginLoad(UIUGens)
470 ft = inTable;
472 pthread_t uiListenThread;
473 pthread_create (&uiListenThread, NULL, gstate_update_func, (void*)0);
475 DefineSimpleUnit(KeyState);
477 DefineUnit("MouseX", sizeof(MouseInputUGen), (UnitCtorFunc)&MouseX_Ctor, 0, 0);
478 DefineUnit("MouseY", sizeof(MouseInputUGen), (UnitCtorFunc)&MouseY_Ctor, 0, 0);
479 DefineUnit("MouseButton", sizeof(MouseInputUGen), (UnitCtorFunc)&MouseButton_Ctor, 0, 0);
481 // define a plugin command - example code
482 gMyPlugin.a = 1.2f;
483 gMyPlugin.b = 3.4f;
484 DefinePlugInCmd("pluginCmdDemo", cmdDemoFunc, (void*)&gMyPlugin);
487 #ifdef __GNUC__
488 #if !defined(__APPLE__) && !defined(_WIN32)
489 static void __attribute__ ((destructor)) finalize(void)
491 if (d)
492 XCloseDisplay(d);
494 #endif
495 #endif