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
23 #include <Carbon/Carbon.h>
28 # include <X11/Intrinsic.h>
34 #include "SC_PlugIn.h"
36 static InterfaceTable
*ft
;
38 struct MouseUGenGlobalState
{
43 struct MouseInputUGen
: public Unit
45 MouseUGenGlobalState
* gstate
;
46 float m_y1
, m_b1
, m_lag
;
49 //////////////////////////////////////////////////////////////////////////////////////////////////
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 //////////////////////////////////////////////////////////////////////////////////////////////////
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
;
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();
91 void* gstate_update_func(void* arg
)
93 MouseUGenGlobalState
* gstate
= &gMouseUGenGlobals
;
94 RgnHandle rgn
= GetGrayRgn();
96 GetRegionBounds(rgn
, &screenBounds
);
97 float rscreenWidth
= 1. / (screenBounds
.right
- screenBounds
.left
);
98 float rscreenHeight
= 1. / (screenBounds
.bottom
- screenBounds
.top
);
102 gstate
->mouseX
= (float)p
.h
* rscreenWidth
;
103 gstate
->mouseY
= (float)p
.v
* rscreenHeight
;
104 gstate
->mouseButton
= Button();
113 #elif defined (_WIN32)
115 void* gstate_update_func(void* arg
)
119 MouseUGenGlobalState
* gstate
;
121 if(GetSystemMetrics(SM_SWAPBUTTON
))
122 mButton
= VK_RBUTTON
; // if swapped
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
;
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.
148 static Display
* d
= 0;
149 void* gstate_update_func(void* arg
)
151 MouseUGenGlobalState
* gstate
;
153 Window rep_root
, rep_child
;
154 XWindowAttributes attributes
;
155 int rep_rootx
, rep_rooty
;
156 unsigned int rep_mask
;
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
);
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
;
178 XQueryPointer ( d
, r
,
179 &rep_root
, &rep_child
,
180 &rep_rootx
, &rep_rooty
,
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
);
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);
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
));
214 float y0
= unit
->gstate
->mouseX
;
216 y0
= (maxval
- minval
) * y0
+ minval
;
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
;
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);
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
));
250 float y0
= unit
->gstate
->mouseY
;
252 y0
= (maxval
- minval
) * y0
+ minval
;
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
;
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);
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
));
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
;
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
310 struct MyCmdData
// data for each command
312 MyPluginData
* myPlugin
;
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
,
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
,
344 // scsynth will perform completion message after this returns
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
,
359 // scsynth will send /done after this returns
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
,
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..
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
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();
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
,
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
)
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
453 DefinePlugInCmd("pluginCmdDemo", cmdDemoFunc
, (void*)&gMyPlugin
);
457 #if !defined(__APPLE__) && !defined(_WIN32)
458 static void __attribute__ ((destructor
)) finalize(void)