An otherwise featureless view that receives extended wacom tablet data. It can also be used with a normal mouse but with less resolution.
To use it in SwingOSC, install the JNI library:
$ cp JNITablet/build/libJNITablet.jnilib /Library/Java/Extensions/
or make a symbolic link:
$ ln -s <absolutePathToSwingOSC>/JNITablet/build/libJNITablet.jnilib /Library/Java/Extensions/
Drag-and-drop returns and accepts a Point, describing the current x and y value.
The default action is triggered when dragging the mouse inside the view.
All the mouse actions ( action, mouseDownAction, and mouseUpAction ) receive the following arguments:
view | the view |
x | subpixel location in view |
y | subpixel location in view |
pressure | 0..1 |
tiltX | -1 (max. left) ... +1 (max. right) |
tiltY | -1 (max. down) ... +1 (max. up) |
deviceID | All tablet-pointer events generated in the period between the device entering and leaving tablet proximity have the same device ID. Therefore, when working with multiple tablets / mice, you can match actions by looking at the deviceID. |
buttonNumber | 0 left, 1 right, 2 middle wheel click. see also buttonMask below. |
clickCount | double click, triple click ... most relevant for the mouseDown, but still valid for the dragged and mouseUp |
absoluteZ | the wheel on the side of some mice |
rotation | in degrees. Used for example on the "4d mouse", and the "art marker". Note: on Mac OS X 10.4.11 using an Intuos3 tablet with Art Marker, the returned value must be multiplied by 1024 to actually obtain degrees (bug?). |
These additional arguments are only delivered in SwingOSC:
absoluteX | the absolute horizontal pen position on tablet (in tablet-native high-resolution) |
absoluteY | the absolute vertical pen position on tablet (in tablet-native high-resolution) |
buttonMask | a flag mask of all buttons on the pen / tablet. you can extract each button's state using a bitAnd: buttonMask.bitAnd( 1 << n ) where n = 0, 1, 2, ... |
tanPressure | Tangential pressure is also known as barrel pressure. |
The action will be called with the following arguments:
view | true to indicate that a pointing device is entering the proximity of its tablet and false when it is leaving it. |
entering | true to indicate that a pointing device is entering the proximity of its tablet and false when it is leaving it. |
deviceID | All tablet-pointer events generated in the period between the device entering and leaving tablet proximity have the same device ID. Therefore, when working with multiple tablets / mice, you can match actions by looking at the deviceID. |
pointingDeviceTypes | 0 NSUnknownPointingDevice 1 NSPenPointingDevice 2 NSCursorPointingDevice 3 NSEraserPointingDevice |
systemTabletID | If multiple tablets are connected to the system, the system-tablet ID is incremented for each subsequent one. If there is only one tablet device, its system-tablet ID is zero. |
pointingDeviceID | This index is significant for multimode (or Dual Tracking) tablets that support multiple concurrent pointing devices; the index is incremented for each pointing device that comes into proximity. Otherwise, zero is always returned. |
tabletID | Returns the USB model identifier of the tablet device associated with the receiver. |
uniqueID | Also known as tool ID, this is a unique number recorded in the chip inside every pointing device. The unique ID makes it possible to assign a specific pointing device to a specific tablet. |
( w = Window.new; t = TabletView(w,Rect(40,40,300,300)); t.background = Color.white; w.acceptsMouseOver = true; w.front; f = { arg what, x, y, pressure, tiltx, tilty, deviceID, buttonNumber, clickCount, absoluteZ, rotation, absoluteX, absoluteY, buttonMask, tanPressure; ("%: x % y % press % tiltx % tilty % clicks % absX % absY % absZ % rota % mask %\n") .postf( what, x.round( 0.01 ), y.round( 0.01 ), pressure.round( 0.01 ), tiltx.round( 0.01 ), tilty.round( 0.01 ), clickCount, absoluteX, absoluteY, absoluteZ, rotation.round( 0.01 ), buttonMask ); }; t.mouseDownAction = { arg view ... params; f.value( "down", *params )}; t.action = { arg view ... params; f.value( "drag", *params )}; t.mouseUpAction = { arg view ... params; f.value( "up ", *params )}; t.mouseOverAction = { arg view ... params; f.value( "over", *params )}; )
s.boot ( SynthDef("help-2DTabletSlider", { arg freq = 440, int1 = 5, int2 = -5, ffreqInterval = 0, rq = 0.4, gate = 0.0; var p,c,d,f; c=LFNoise1.kr(0.1,0.45,0.55); d=LFNoise1.kr(0.1,0.45,0.55); f=LFNoise1.kr(0.1,2); p=Pulse.ar([ freq * int1.midiratio + f , freq, freq * int2.midiratio - f], [c,d,c], 0.2); Out.ar(0, RLPF.ar(Mix.ar(p),freq * ffreqInterval.midiratio,rq) * EnvGen.kr(Env.adsr, gate, gate) ) },[0.1,0.1,0.1,0.1,0.1,nil]).add; ) ( var w, v,freq,int,synth; synth = Synth("help-2DTabletSlider"); w = Window.new.front; freq = ControlSpec(100,3000,\exp); int = ControlSpec(-48,48,\linear,1); v = TabletView(w,Rect(10,10,380,380)); v.background = Color.blue.alpha_(0.2); v.action = { arg view,x,y,pressure,tiltx,tilty; synth.set( \int1, int.map(x), \int2, int.map(y), \ffreqInterval, int.map(pressure), \gate, pressure.postln ); }; v.mouseDownAction = { arg view,x,y,pressure; synth.set( \freq , rrand(30,80).midicps, \gate, pressure.postln ) }; v.mouseUpAction = { arg view,x,y,pressure; synth.set( \gate, 0.postln ) }; )
( w = JSCWindow.new; t = JSCTabletView(w,Rect(40,40,300,300)); t.background = Color.white; w.acceptsMouseOver = true; w.front; t.proximityAction = { arg view, entering, deviceID, pointingDeviceType, systemTabletID, pointingDeviceID, tabletID, uniqueID; var what = if( entering, "enter", "exit " ); ("%: deviceID % pointingDeviceType % systemTabletID % pointingDeviceID % tabletID % uniqueID %\n") .postf( what, deviceID, pointingDeviceType, systemTabletID, pointingDeviceID, tabletID, uniqueID ); }; )
( var x = 150, y = 150, pressure = 0, tiltx = 0, tilty = 0, rota = 0, colr = Color.white; w = JSCWindow.new; t = JSCTabletView( w,Rect( 40, 40, 300, 300 )); t.background = Color.white; w.front; f = { arg view, argX, argY, argPressure, argTiltX, argTiltY, deviceID, buttonNumber, clickCount, absZ, argRota; x = argX; y = argY; pressure = argPressure; tiltx = argTiltX; tilty = argTiltY; rota = argRota * 1024; // * 1024 for Art Marker... view.refresh; }; t.drawFunc = { arg view; JPen.fillColor = colr; JPen.fillRect( view.bounds.moveTo( 0, 0 )); JPen.translate( x, y ); JPen.width = pressure * 10 + 0.5; JPen.rotate( rota * pi / 180 ); JPen.skew( tiltx, tilty ); JPen.strokeOval( Rect( -100, -100, 200, 200 )); JPen.line( -100 @ 0, 100 @ 0 ); JPen.line( 0 @ -100, 0 @ 100 ); JPen.stroke; }; t.mouseDownAction = f; t.action = f; t.mouseUpAction = f; t.proximityAction = { arg view, entering, deviceID, pointingDeviceType; colr = if( entering, { Color.hsv( pointingDeviceType / 4, 0.5, 1.0 )}, Color.white ); view.refresh; }; )
Here's a variation: make the above example respond only to a particular pen tools. For this, you need a pen that fires proximity actions and you need to know the pen's uniqueID (see -proximityAction). For example, my Art Marker has ID 127926421:
( var filterUniqueID = 127926421; // put your own ID here var filterDeviceID = -1; var fProx, fAction; fProx = t.proximityAction; t.proximityAction = { arg view, entering, deviceID, pointingDeviceType, systemTabletID, pointingDeviceID, tabletID, uniqueID; if( uniqueID == filterUniqueID, { filterDeviceID = deviceID; // now t.action only reacts to events from this deviceID fProx.value( view, entering, deviceID, pointingDeviceType ); }); }; fAction = t.action; f = { arg view, x, y, pressure, tiltX, tiltY, deviceID, buttonNumber, clickCount, absZ, rota; if( deviceID == filterDeviceID, { fAction.value( view, x, y, pressure, tiltX, tiltY, deviceID, buttonNumber, clickCount, absZ, rota ); }); }; t.mouseDownAction = f; t.action = f; t.mouseUpAction = f; )
( Instr([\minimoog,\loose],{ arg freq=440,int1=5,int2 = -5, ffreqInterval=0,rq=0.4,gate=0.0; var p,c,d,f; c=LFNoise1.kr(0.1,0.45,0.55); d=LFNoise1.kr(0.1,0.45,0.55); f=LFNoise1.kr(0.1,2); p=Pulse.ar([ freq * int1.midiratio + f , freq, freq * int2.midiratio - f], [c,d,c],0.2); RLPF.ar(Mix.ar(p),freq * ffreqInterval.midiratio,rq) * EnvGen.kr(Env.adsr, gate, Latch.kr(gate,gate)) },#[ nil, [[-48,48,\linear,1]], [[-48,48,\linear,1]], [[-48,48,\linear,1]] ]); p = Patch.new([ 'minimoog', 'loose' ],[ nil,nil,nil,nil,nil, KrNumberEditor(0.0,\gate) // override the default control ]); Sheet({ arg f; var v,freq,int; freq = ControlSpec(100,3000,\exp); int = [-48,48,\linear,1].asSpec; p.topGui(f); v = TabletView(f,Rect(0,0,200,200)); v.background = Color.white; v.action = { arg view,x,y,pressure,tiltx,tilty; p.args.at(1).value_( int.map( x / 200 ) ).changed; p.args.at(2).value_( int.map( y / 200 ) ).changed; p.args.at(3).value_( int.map( pressure ) ).changed; }; v.mouseDownAction = { arg view,x,y,pressure; p.args.at(0).value_( rrand(30,80).midicps ).changed; p.args.at(5).value_( pressure ).changed; }; v.mouseUpAction = { arg view,x,y,pressure; p.args.at(5).value_( 0.0 ).changed; }; }); )