class library: SynthDef - replaceUGen fixes
[supercollider.git] / server / plugins / MouseUGens.cpp
blob4908de6518e0310c0898dee547e21fc58df5c168
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 MouseUGenGlobalState {
39 float mouseX, mouseY;
40 bool mouseButton;
41 } gMouseUGenGlobals;
43 struct MouseInputUGen : public Unit
45 MouseUGenGlobalState* gstate;
46 float m_y1, m_b1, m_lag;
49 //////////////////////////////////////////////////////////////////////////////////////////////////
51 extern "C"
53 void MouseX_next(MouseInputUGen *unit, int inNumSamples);
54 void MouseY_next(MouseInputUGen *unit, int inNumSamples);
55 void MouseButton_next(MouseInputUGen *unit, int inNumSamples);
57 void MouseX_Ctor(MouseInputUGen *unit);
58 void MouseY_Ctor(MouseInputUGen *unit);
59 void MouseButton_Ctor(MouseInputUGen *unit);
62 //////////////////////////////////////////////////////////////////////////////////////////////////
64 #ifdef __APPLE__
65 # if (__x86_64__)
67 void* gstate_update_func(void* arg)
69 MouseUGenGlobalState* gstate = &gMouseUGenGlobals;
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 for (;;) {
76 HIPoint point;
77 HICoordinateSpace space = 2;
78 HIGetMousePosition(space, NULL, &point);
80 gstate->mouseX = point.x * rscreenWidth; //(float)p.h * rscreenWidth;
81 gstate->mouseY = point.y * rscreenHeight; //(float)p.v * rscreenHeight;
82 gstate->mouseButton = Button();
83 usleep(17000);
86 return 0;
89 # else
91 void* gstate_update_func(void* arg)
93 MouseUGenGlobalState* gstate = &gMouseUGenGlobals;
94 RgnHandle rgn = GetGrayRgn();
95 Rect screenBounds;
96 GetRegionBounds(rgn, &screenBounds);
97 float rscreenWidth = 1. / (screenBounds.right - screenBounds.left);
98 float rscreenHeight = 1. / (screenBounds.bottom - screenBounds.top);
99 for (;;) {
100 Point p;
101 GetGlobalMouse(&p);
102 gstate->mouseX = (float)p.h * rscreenWidth;
103 gstate->mouseY = (float)p.v * rscreenHeight;
104 gstate->mouseButton = Button();
105 usleep(17000);
108 return 0;
111 # endif
113 #elif defined (_WIN32)
115 void* gstate_update_func(void* arg)
117 POINT p;
118 int mButton;
119 MouseUGenGlobalState* gstate;
121 if(GetSystemMetrics(SM_SWAPBUTTON))
122 mButton = VK_RBUTTON; // if swapped
123 else
124 mButton = VK_LBUTTON; // not swapped (normal)
126 int screenWidth = GetSystemMetrics( SM_CXSCREEN );
127 int screenHeight = GetSystemMetrics( SM_CYSCREEN );
128 // default: SM_CX/CYSCREEN gets the size of a primary screen.
129 // lines uncommented below are just for a specially need on multi-display.
130 //int screenWidth = GetSystemMetrics( SM_CXVIRTUALSCREEN );
131 //int screenHeight = GetSystemMetrics( SM_CYVIRTUALSCREEN );
132 float r_screenWidth = 1.f / (float)(screenWidth -1);
133 float r_screenHeight = 1.f / (float)(screenHeight -1);
135 gstate = &gMouseUGenGlobals;
137 for(;;) {
138 GetCursorPos(&p);
139 gstate->mouseX = (float)p.x * r_screenWidth;
140 gstate->mouseY = 1.f - (float)p.y * r_screenHeight;
141 gstate->mouseButton = (GetKeyState(mButton) < 0);
142 ::Sleep(17); // 17msec.
144 return 0;
147 # else
148 static Display * d = 0;
149 void* gstate_update_func(void* arg)
151 MouseUGenGlobalState* gstate;
152 Window r;
153 Window rep_root, rep_child;
154 XWindowAttributes attributes;
155 int rep_rootx, rep_rooty ;
156 unsigned int rep_mask;
157 int dx, dy;
158 float r_width;
159 float r_height;
160 struct timespec requested_time, remaining_time;
162 requested_time.tv_sec = 0;
163 requested_time.tv_nsec = 17000 * 1000;
165 XInitThreads(); // x api is called by both mouse and keyboard ugens
167 d = XOpenDisplay ( NULL );
168 if (!d) return 0;
170 r = DefaultRootWindow ( d );
171 XGetWindowAttributes ( d, r, &attributes );
172 r_width = 1.0 / (float)attributes.width;
173 r_height = 1.0 / (float)attributes.height;
175 gstate = &gMouseUGenGlobals;
177 for (;;) {
178 XQueryPointer ( d, r,
179 &rep_root, &rep_child,
180 &rep_rootx, &rep_rooty,
181 &dx, &dy,
182 &rep_mask);
184 gstate->mouseX = (float)dx * r_width;
185 gstate->mouseY = 1.f - ( (float)dy * r_height );
187 gstate->mouseButton = (bool) ( rep_mask & Button1Mask );
189 nanosleep ( &requested_time , &remaining_time );
192 return 0;
194 #endif
196 //////////////////////////////////////////////////////////////////////////////////////////////////
198 void MouseX_next(MouseInputUGen *unit, int inNumSamples)
200 // minval, maxval, warp, lag
202 float minval = ZIN0(0);
203 float maxval = ZIN0(1);
204 float warp = ZIN0(2);
205 float lag = ZIN0(3);
207 float y1 = unit->m_y1;
208 float b1 = unit->m_b1;
210 if (lag != unit->m_lag) {
211 unit->m_b1 = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate));
212 unit->m_lag = lag;
214 float y0 = unit->gstate->mouseX;
215 if (warp == 0.0) {
216 y0 = (maxval - minval) * y0 + minval;
217 } else {
218 y0 = pow(maxval/minval, y0) * minval;
220 ZOUT0(0) = y1 = y0 + b1 * (y1 - y0);
221 unit->m_y1 = zapgremlins(y1);
224 void MouseX_Ctor(MouseInputUGen *unit)
226 SETCALC(MouseX_next);
227 unit->gstate = &gMouseUGenGlobals;
228 unit->m_b1 = 0.f;
229 unit->m_lag = 0.f;
230 MouseX_next(unit, 1);
234 void MouseY_next(MouseInputUGen *unit, int inNumSamples)
236 // minval, maxval, warp, lag
238 float minval = ZIN0(0);
239 float maxval = ZIN0(1);
240 float warp = ZIN0(2);
241 float lag = ZIN0(3);
243 float y1 = unit->m_y1;
244 float b1 = unit->m_b1;
246 if (lag != unit->m_lag) {
247 unit->m_b1 = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate));
248 unit->m_lag = lag;
250 float y0 = unit->gstate->mouseY;
251 if (warp == 0.0) {
252 y0 = (maxval - minval) * y0 + minval;
253 } else {
254 y0 = pow(maxval/minval, y0) * minval;
256 ZOUT0(0) = y1 = y0 + b1 * (y1 - y0);
257 unit->m_y1 = zapgremlins(y1);
260 void MouseY_Ctor(MouseInputUGen *unit)
262 SETCALC(MouseY_next);
263 unit->gstate = &gMouseUGenGlobals;
264 unit->m_b1 = 0.f;
265 unit->m_lag = 0.f;
266 MouseY_next(unit, 1);
270 void MouseButton_next(MouseInputUGen *unit, int inNumSamples)
272 // minval, maxval, warp, lag
274 float minval = ZIN0(0);
275 float maxval = ZIN0(1);
276 float lag = ZIN0(2);
278 float y1 = unit->m_y1;
279 float b1 = unit->m_b1;
281 if (lag != unit->m_lag) {
282 unit->m_b1 = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate));
283 unit->m_lag = lag;
285 float y0 = unit->gstate->mouseButton ? maxval : minval;
286 ZOUT0(0) = y1 = y0 + b1 * (y1 - y0);
287 unit->m_y1 = zapgremlins(y1);
290 void MouseButton_Ctor(MouseInputUGen *unit)
292 SETCALC(MouseButton_next);
293 unit->gstate = &gMouseUGenGlobals;
294 unit->m_b1 = 0.f;
295 unit->m_lag = 0.f;
296 MouseButton_next(unit, 1);
299 //////////////////////////////////////////////////////////////////////////////////////////////////
300 //////////////////////////////////////////////////////////////////////////////////////////////////
301 //////////////////////////////////////////////////////////////////////////////////////////////////
303 // example of implementing a plug in command with async execution.
305 struct MyPluginData // data for the global instance of the plugin
307 float a, b;
310 struct MyCmdData // data for each command
312 MyPluginData* myPlugin;
313 float x, y;
314 char *name;
317 MyPluginData gMyPlugin; // global
319 bool cmdStage2(World* world, void* inUserData)
321 // user data is the command.
322 MyCmdData* myCmdData = (MyCmdData*)inUserData;
324 // just print out the values
325 Print("cmdStage2 a %g b %g x %g y %g name %s\n",
326 myCmdData->myPlugin->a, myCmdData->myPlugin->b,
327 myCmdData->x, myCmdData->y,
328 myCmdData->name);
330 return true;
333 bool cmdStage3(World* world, void* inUserData)
335 // user data is the command.
336 MyCmdData* myCmdData = (MyCmdData*)inUserData;
338 // just print out the values
339 Print("cmdStage3 a %g b %g x %g y %g name %s\n",
340 myCmdData->myPlugin->a, myCmdData->myPlugin->b,
341 myCmdData->x, myCmdData->y,
342 myCmdData->name);
344 // scsynth will perform completion message after this returns
345 return true;
348 bool cmdStage4(World* world, void* inUserData)
350 // user data is the command.
351 MyCmdData* myCmdData = (MyCmdData*)inUserData;
353 // just print out the values
354 Print("cmdStage4 a %g b %g x %g y %g name %s\n",
355 myCmdData->myPlugin->a, myCmdData->myPlugin->b,
356 myCmdData->x, myCmdData->y,
357 myCmdData->name);
359 // scsynth will send /done after this returns
360 return true;
363 void cmdCleanup(World* world, void* inUserData)
365 // user data is the command.
366 MyCmdData* myCmdData = (MyCmdData*)inUserData;
368 Print("cmdCleanup a %g b %g x %g y %g name %s\n",
369 myCmdData->myPlugin->a, myCmdData->myPlugin->b,
370 myCmdData->x, myCmdData->y,
371 myCmdData->name);
373 RTFree(world, myCmdData->name); // free the string
374 RTFree(world, myCmdData); // free command data
375 // scsynth will delete the completion message for you.
378 void cmdDemoFunc(World *inWorld, void* inUserData, struct sc_msg_iter *args, void *replyAddr)
380 Print("->cmdDemoFunc %p\n", inUserData);
382 // user data is the plug-in's user data.
383 MyPluginData* thePlugInData = (MyPluginData*)inUserData;
385 // allocate command data, free it in cmdCleanup.
386 MyCmdData* myCmdData = (MyCmdData*)RTAlloc(inWorld, sizeof(MyCmdData));
387 myCmdData->myPlugin = thePlugInData;
389 // ..get data from args..
390 myCmdData->x = 0.;
391 myCmdData->y = 0.;
392 myCmdData->name = 0;
394 // float arguments
395 myCmdData->x = args->getf();
396 myCmdData->y = args->getf();
398 // how to pass a string argument:
399 const char *name = args->gets(); // get the string argument
400 if (name) {
401 myCmdData->name = (char*)RTAlloc(inWorld, strlen(name)+1); // allocate space, free it in cmdCleanup.
402 strcpy(myCmdData->name, name); // copy the string
405 // how to pass a completion message
406 int msgSize = args->getbsize();
407 char* msgData = 0;
408 if (msgSize) {
409 // allocate space for completion message
410 // scsynth will delete the completion message for you.
411 msgData = (char*)RTAlloc(inWorld, msgSize);
412 args->getb(msgData, msgSize); // copy completion message.
415 DoAsynchronousCommand(inWorld, replyAddr, "cmdDemoFunc", (void*)myCmdData,
416 (AsyncStageFn)cmdStage2,
417 (AsyncStageFn)cmdStage3,
418 (AsyncStageFn)cmdStage4,
419 cmdCleanup,
420 msgSize, msgData);
422 Print("<-cmdDemoFunc\n");
426 to test the above, send the server these commands:
429 SynthDef(\sine, { Out.ar(0, SinOsc.ar(800,0,0.2)) }).load(s);
430 s.sendMsg(\cmd, \pluginCmdDemo, 7, 9, \mno, [\s_new, \sine, 900, 0, 0]);
431 s.sendMsg(\n_free, 900);
432 s.sendMsg(\cmd, \pluginCmdDemo, 7, 9, \mno);
433 s.sendMsg(\cmd, \pluginCmdDemo, 7, 9);
434 s.sendMsg(\cmd, \pluginCmdDemo, 7);
435 s.sendMsg(\cmd, \pluginCmdDemo);
439 PluginLoad(MouseUGens)
441 ft = inTable;
443 pthread_t mouseListenThread;
444 pthread_create (&mouseListenThread, NULL, gstate_update_func, (void*)0);
446 DefineUnit("MouseX", sizeof(MouseInputUGen), (UnitCtorFunc)&MouseX_Ctor, 0, 0);
447 DefineUnit("MouseY", sizeof(MouseInputUGen), (UnitCtorFunc)&MouseY_Ctor, 0, 0);
448 DefineUnit("MouseButton", sizeof(MouseInputUGen), (UnitCtorFunc)&MouseButton_Ctor, 0, 0);
450 // define a plugin command - example code
451 gMyPlugin.a = 1.2f;
452 gMyPlugin.b = 3.4f;
453 DefinePlugInCmd("pluginCmdDemo", cmdDemoFunc, (void*)&gMyPlugin);
456 #ifdef __GNUC__
457 #if !defined(__APPLE__) && !defined(_WIN32)
458 static void __attribute__ ((destructor)) finalize(void)
460 if (d)
461 XCloseDisplay(d);
463 #endif
464 #endif