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 KeyboardUGenGlobalState
{
47 struct KeyState
: public Unit
49 float m_y1
, m_b1
, m_lag
;
53 struct MouseUGenGlobalState
{
58 struct MouseInputUGen
: public Unit
60 float m_y1
, m_b1
, m_lag
;
64 //////////////////////////////////////////////////////////////////////////////////////////////////
68 void* gstate_update_func(void* arg
)
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
;
76 RgnHandle rgn
= GetGrayRgn();
78 GetRegionBounds(rgn
, &screenBounds
);
79 float rscreenWidth
= 1. / (screenBounds
.right
- screenBounds
.left
);
80 float rscreenHeight
= 1. / (screenBounds
.bottom
- screenBounds
.top
);
83 GetKeys(gKeyStateGlobals
.keys
);
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();
96 gMouseUGenGlobals
.mouseX
= (float)p
.h
* rscreenWidth
;
97 gMouseUGenGlobals
.mouseY
= (float)p
.v
* rscreenHeight
;
98 gMouseUGenGlobals
.mouseButton
= Button();
106 #elif defined(_WIN32)
108 void* gstate_update_func(void* arg
)
113 if(GetSystemMetrics(SM_SWAPBUTTON
))
114 mButton
= VK_RBUTTON
; // if swapped
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);
129 // "KeyState" is disabled for now, on Windows...
130 //GetKey((long*)gstate->keys);
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.
142 static Display
* d
= 0;
143 void* gstate_update_func(void* arg
)
146 struct timespec requested_time
, remaining_time
;
148 requested_time
.tv_sec
= 0;
149 requested_time
.tv_nsec
= 17000 * 1000;
151 d
= XOpenDisplay ( NULL
);
154 Window rep_root
, rep_child
;
155 XWindowAttributes attributes
;
156 int rep_rootx
, rep_rooty
;
157 unsigned int rep_mask
;
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
;
168 XQueryKeymap ( d
, (char *) (gKeyStateGlobals
.keys
) );
169 XQueryPointer ( d
, r
,
170 &rep_root
, &rep_child
,
171 &rep_rootx
, &rep_rooty
,
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
);
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);
195 int byte
= (keynum
>> 3) & 15;
197 int byte
= (keynum
>> 3) & 31;
199 int bit
= keynum
& 7;
200 int val
= keys
[byte
] & (1 << bit
);
202 float minval
= ZIN0(1);
203 float maxval
= ZIN0(2);
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
));
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
);
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);
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
));
244 float y0
= gMouseUGenGlobals
.mouseX
;
246 y0
= (maxval
- minval
) * y0
+ minval
;
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
);
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);
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
));
279 float y0
= gMouseUGenGlobals
.mouseY
;
281 y0
= (maxval
- minval
) * y0
+ minval
;
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
);
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);
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
));
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
);
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
337 struct MyCmdData
// data for each command
339 MyPluginData
* myPlugin
;
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
,
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
,
371 // scsynth will perform completion message after this returns
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
,
386 // scsynth will send /done after this returns
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
,
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..
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
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();
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
,
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);
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
484 DefinePlugInCmd("pluginCmdDemo", cmdDemoFunc
, (void*)&gMyPlugin
);
488 #if !defined(__APPLE__) && !defined(_WIN32)
489 static void __attribute__ ((destructor
)) finalize(void)