wiimote-0.3.2/0000755000175000017500000000000011440155633012205 5ustar romanromanwiimote-0.3.2/README0000644000175000017500000000267511432457065013104 0ustar romanromanwiimote for Pd ============== [wiimote] is a Pd-object that allows to read data from a Wii Remote Controller it depends on libcwiid, which is currently only available on linux random notes ============ extensions ---------- the external is known to support the nunchuck, classic, motionplus extensions the balance extension might work, but is currently untested (if it doesn't work and you need it, contact me to and send me the hardware) motionplus ---------- the motionplus extension for the wiimote is supported (out of the box, see above). however, older releases of libcwiid are inaccurate at detecting rotation speed (the wii remote reports whether the controller is turned fast or slow; this info is missing in libcwiid). if you have such a version of libcwiid and need higher precision, you have to patch the sources of libcwiid: $ cd /path/to/cwiid/libcwiid $ patch < /path/to/wiimote/patches/cwiid201_motionplus_sensitivity.patch $ cd /path/to/cwiid/ $ make (read README to see how to patch libcwiid) once you have done that, you need to make the external aware of the new feature. for this create a file /path/to/wiimote/Make.local and add the following line: CFLAGS += -DHAVE_CWIID_MOTIONPLUS_LOWSPEED then recompile wiimote multiple bluetooth dongles -------------------------- [LATER describe that] contact ======= get in contact with me either via the pd-list (http://lists.puredata.info/listinfo/pd-list) or directly via zmoelnig[at]iem[.]at wiimote-0.3.2/CHANGES0000644000175000017500000000002411432457065013201 0ustar romanromaninitial release 0.3 wiimote-0.3.2/version_update.sh0000644000175000017500000000030411432457065015572 0ustar romanroman#!/bin/sh VERSION=$(cat VERSION) echo updating to version: $VERSION sed -e "s|^VERSION=.*$|VERSION=${VERSION}|" -i Makefile sed -e "s| VERSION .*;$| VERSION ${VERSION};|" -i wiimote-meta.pd wiimote-0.3.2/motionplus_rate2angle.pd0000644000175000017500000000540511262703374017056 0ustar romanroman#N canvas 0 0 450 357 10; #N canvas 0 0 704 467 anglespeed 0; #X obj 149 57 loadbang; #X obj 95 108 t l l; #X msg 95 85 \$2 \$1; #X obj 127 151 route 1; #X obj 95 232 unpack; #X obj 95 255 pack; #X obj 95 277 route 0 1; #X obj 95 299 / 4; #X obj 95 321 t f; #X obj 125 299 / 20; #X obj 149 78 t b b; #X obj 149 100 f 8063; #X obj 134 254 - 8063; #X msg 149 122 set \$1; #X obj 95 36 inlet ; #X obj 95 393 outlet; #X obj 127 173 mavg 1000; #X obj 346 58 r \$0-reset; #X obj 173 223 t f f; #X obj 173 201 f 8063; #X connect 0 0 10 0; #X connect 1 0 4 0; #X connect 1 1 3 0; #X connect 2 0 1 0; #X connect 3 0 16 0; #X connect 4 0 5 0; #X connect 4 1 12 0; #X connect 5 0 6 0; #X connect 6 0 7 0; #X connect 6 1 9 0; #X connect 7 0 8 0; #X connect 8 0 15 0; #X connect 9 0 8 0; #X connect 10 0 11 0; #X connect 10 1 19 0; #X connect 11 0 13 0; #X connect 12 0 5 1; #X connect 13 0 16 0; #X connect 14 0 2 0; #X connect 16 0 19 1; #X connect 17 0 10 0; #X connect 18 0 12 1; #X connect 18 1 11 1; #X connect 19 0 18 0; #X restore 51 155 pd anglespeed; #N canvas 0 0 450 300 deadzone 0; #X obj 90 101 t f; #X obj 90 123 moses -0.5; #X obj 157 144 moses 0.5; #X msg 157 166 0; #X obj 158 104 * -1; #X obj 157 188 t f; #X obj 157 210 outlet; #X obj 158 82 t f f; #X obj 90 46 inlet dphi; #X obj 225 45 r \$0-deadzone; #X connect 0 0 1 0; #X connect 1 0 5 0; #X connect 1 1 2 0; #X connect 2 0 3 0; #X connect 2 1 5 0; #X connect 3 0 5 0; #X connect 4 0 1 1; #X connect 5 0 6 0; #X connect 7 0 4 0; #X connect 7 1 2 1; #X connect 8 0 0 0; #X connect 9 0 7 0; #X restore 51 202 pd deadzone; #N canvas 0 0 450 300 accumulate 0; #X obj 95 179 t f; #X obj 95 201 +; #X obj 95 223 t f f; #X msg 143 180 0; #X obj 95 156 inlet; #X obj 95 245 outlet; #X obj 143 161 r \$0-reset; #X connect 0 0 1 0; #X connect 1 0 2 0; #X connect 2 0 5 0; #X connect 2 1 1 1; #X connect 3 0 1 1; #X connect 4 0 0 0; #X connect 6 0 3 0; #X restore 51 257 pd accumulate; #N canvas 0 0 1087 300 pertime 0; #X obj 83 53 inlet; #X obj 83 75 t f; #X obj 83 97 / 100; #X obj 83 119 outlet; #X text 137 96 <-- currently hardcoded to 10 fps \; LATER make use of the timetags in the cwiid message and see whether this helps; #X connect 0 0 1 0; #X connect 1 0 2 0; #X connect 2 0 3 0; #X restore 51 177 pd pertime; #X obj 268 137 route reset deadzone; #X obj 268 159 t b; #X obj 268 181 s \$0-reset; #X obj 268 115 inlet control; #X obj 51 128 inlet angle_rate; #X obj 51 279 outlet angle; #X obj 336 212 t f; #X obj 336 234 s \$0-deadzone; #X obj 183 279 outlet dAngle; #X obj 51 229 t f f; #X connect 0 0 3 0; #X connect 1 0 13 0; #X connect 2 0 9 0; #X connect 3 0 1 0; #X connect 4 0 5 0; #X connect 4 1 10 0; #X connect 5 0 6 0; #X connect 7 0 4 0; #X connect 8 0 0 0; #X connect 10 0 11 0; #X connect 13 0 2 0; #X connect 13 1 12 0; wiimote-0.3.2/VERSION0000644000175000017500000000000611437671315013257 0ustar romanroman0.3.2 wiimote-0.3.2/wiimote-meta.pd0000644000175000017500000000036711437671315015147 0ustar romanroman#N canvas 16 114 200 200 10; #N canvas 488 184 420 300 META 1; #X text 13 41 NAME wiimote; #X text 10 25 AUTHOR Mike Wozniewski + Florian Krebs + IOhannes m zmoelnig ; #X text 10 10 VERSION 0.3.2; #X obj 163 144 wiimote; #X restore 10 10 pd META; wiimote-0.3.2/patches/0000755000175000017500000000000011440155633013634 5ustar romanromanwiimote-0.3.2/patches/cwiid201_motionplus_sensitivity.patch0000644000175000017500000000310611262670424023144 0ustar romanromanIndex: process.c =================================================================== --- process.c (revision 201) +++ process.c (working copy) @@ -249,6 +249,9 @@ (uint16_t)data[1]; motionplus_mesg->angle_rate[CWIID_PSI] = ((uint16_t)data[3] & 0xFC)<<6 | (uint16_t)data[0]; + motionplus_mesg->low_speed[CWIID_PHI] = ((uint8_t)data[3] & 0x01); + motionplus_mesg->low_speed[CWIID_THETA] = ((uint8_t)data[4] & 0x02)>>1; + motionplus_mesg->low_speed[CWIID_PSI] = ((uint8_t)data[3] & 0x02)>>1; } break; } Index: state.c =================================================================== --- state.c (revision 201) +++ state.c (working copy) @@ -85,6 +85,9 @@ memcpy(wiimote->state.ext.motionplus.angle_rate, mesg->motionplus_mesg.angle_rate, sizeof wiimote->state.ext.motionplus.angle_rate); + memcpy(wiimote->state.ext.motionplus.low_speed, + mesg->motionplus_mesg.low_speed, + sizeof wiimote->state.ext.motionplus.low_speed); break; case CWIID_MESG_ERROR: wiimote->state.error = mesg->error_mesg.error; Index: cwiid.h =================================================================== --- cwiid.h (revision 201) +++ cwiid.h (working copy) @@ -263,6 +263,7 @@ struct cwiid_motionplus_mesg { enum cwiid_mesg_type type; uint16_t angle_rate[3]; + uint8_t low_speed[3]; }; struct cwiid_error_mesg { @@ -307,6 +308,7 @@ struct motionplus_state { uint16_t angle_rate[3]; + uint8_t low_speed[3]; }; union ext_state { wiimote-0.3.2/motionplus.pd0000644000175000017500000001213311263116657014751 0ustar romanroman#N canvas 325 242 656 565 10; #X obj 51 48 inlet wiimotionplus; #X obj 51 70 route wiimotionplus; #X text 196 39 just in case somebody uses the [wiimote]s output directly ; #N canvas 676 229 450 300 slowfast 0; #X obj 105 55 inlet; #X obj 105 77 route angle_rate low_speed; #X obj 105 107 unpack 0 0 0; #X obj 194 107 unpack 0 0 0; #X obj 105 232 pack; #X obj 105 254 outlet pitch; #X obj 195 232 pack; #X obj 278 232 pack; #X obj 195 254 outlet roll; #X obj 278 254 outlet yaw; #X connect 0 0 1 0; #X connect 1 0 2 0; #X connect 1 1 3 0; #X connect 2 0 4 0; #X connect 2 1 6 0; #X connect 2 2 7 0; #X connect 3 0 4 1; #X connect 3 1 6 1; #X connect 3 2 7 1; #X connect 4 0 5 0; #X connect 6 0 8 0; #X connect 7 0 9 0; #X restore 51 98 pd slowfast; #X obj 51 297 pack 0 0 0; #X obj 51 120 motionplus_rate2angle; #X obj 51 319 outlet yaw roll pitch; #X obj 218 230 pack 0 0 0; #X obj 242 118 t a a a; #X msg 242 85 reset; #X msg 300 95 deadzone \$1; #X floatatom 300 75 5 0 0 0 - - -; #X obj 218 322 outlet dYaw dRoll dPitch; #X obj 88 150 motionplus_rate2angle; #X obj 125 180 motionplus_rate2angle; #N canvas 0 0 450 300 angleaxis 0; #X obj 142 209 mtx_*; #X obj 142 231 t a a; #X obj 273 154 loadbang; #X msg 142 155 \$1 0 0; #N canvas 295 417 569 550 angleaxis2mtx 0; #X obj 73 43 inlet dYaw dRoll dPitch; #N canvas 0 0 450 300 length 0; #X obj 84 59 t f f; #X obj 84 81 *; #X obj 84 103 +; #X obj 84 125 outlet; #X obj 134 59 t f f; #X obj 134 81 *; #X obj 134 103 +; #X obj 184 59 t f f; #X obj 184 81 *; #X obj 84 37 unpack 0 0 0; #X obj 84 15 inlet; #X connect 0 0 1 0; #X connect 0 1 1 1; #X connect 1 0 2 0; #X connect 2 0 3 0; #X connect 4 0 5 0; #X connect 4 1 5 1; #X connect 5 0 6 0; #X connect 6 0 2 1; #X connect 7 0 8 0; #X connect 7 1 8 1; #X connect 8 0 6 1; #X connect 9 0 0 0; #X connect 9 1 4 0; #X connect 9 2 7 0; #X connect 10 0 9 0; #X restore 105 84 pd length; #X obj 73 65 t l l; #N canvas 0 0 450 300 normalize 0; #X obj 74 36 inlet; #X obj 74 58 unpack 0 0 0; #X obj 74 102 pack 0 0 0; #X obj 74 124 outlet; #X obj 74 80 * 1; #X obj 114 80 * 1; #X obj 155 80 * 1; #X obj 261 33 inlet length; #X msg 261 55 1 \$1; #X obj 261 77 /; #X obj 165 57 t f f f; #X connect 0 0 1 0; #X connect 1 0 4 0; #X connect 1 1 5 0; #X connect 1 2 6 0; #X connect 2 0 3 0; #X connect 4 0 2 0; #X connect 5 0 2 1; #X connect 6 0 2 2; #X connect 7 0 8 0; #X connect 8 0 9 0; #X connect 9 0 10 0; #X connect 10 0 4 1; #X connect 10 1 5 1; #X connect 10 2 6 1; #X restore 73 145 pd normalize; #X obj 105 106 t f f; #N canvas 0 0 450 300 deg2rad 0; #X obj 109 112 inlet deg; #X obj 109 231 outlet rad; #X obj 181 179 / 45; #X obj 181 113 loadbang; #X obj 109 202 * 0.0174533; #X obj 109 178 f; #X text 93 282 rad=deg*pi/180; #X obj 181 156 atan; #X msg 181 135 1; #X text 225 36 part of zexy; #X text 63 66 convert DEGree to RADiant; #X connect 0 0 5 0; #X connect 2 0 4 1; #X connect 3 0 8 0; #X connect 4 0 1 0; #X connect 5 0 4 0; #X connect 7 0 2 0; #X connect 8 0 7 0; #X restore 171 146 pd deg2rad; #X obj 171 168 t f f; #X obj 171 190 cos; #X obj 171 212 t f f; #X obj 203 234 * -1; #X obj 203 256 + 1; #X obj 203 190 sin; #X text 297 81 c=cos() \, s=sin() \, C=1-c; #X text 297 141 [ z*x*C-y*s y*z*C+x*s z*z*C+c ]; #X text 297 100 [ x*x*C+c x*y*C-z*s z*x*C+y*s ]; #X text 297 121 [ x*y*C+z*s y*y*C+c y*z*C-x*s ]; #X obj 73 282 pack 0 0 0 0 0 0; #X obj 310 255 expr; #X obj 73 305 expr $f1*$f1*$f6+$f4 \; $f1*$f2*$f6-$f3*$f5 \; $f1*$f3*$f6+$f2*$f5 \; $f1*$f2*$f6+$f3*$f5 \; $f2*$f2*$f6+$f4 \; $f2*$f3*$f6-$f1*$f5 \; $f1*$f3*$f6-$f2*$f5 \; $f2*$f3*$f6+$f1*$f5 \; $f3*$f3*$f6+$f4; #X obj 73 430 pack 0 0 0 0 0 0 0 0 0; #X obj 73 452 list prepend matrix 3 3; #X obj 73 474 list trim; #X obj 73 496 outlet Rot; #X connect 0 0 2 0; #X connect 1 0 4 0; #X connect 2 0 3 0; #X connect 2 1 1 0; #X connect 3 0 16 0; #X connect 4 0 3 1; #X connect 4 1 5 0; #X connect 5 0 6 0; #X connect 6 0 7 0; #X connect 6 1 11 0; #X connect 7 0 8 0; #X connect 8 0 16 3; #X connect 8 1 9 0; #X connect 9 0 10 0; #X connect 10 0 16 5; #X connect 11 0 16 4; #X connect 16 0 18 0; #X connect 18 0 19 0; #X connect 18 1 19 1; #X connect 18 2 19 2; #X connect 18 3 19 3; #X connect 18 4 19 4; #X connect 18 5 19 5; #X connect 18 6 19 6; #X connect 18 7 19 7; #X connect 18 8 19 8; #X connect 19 0 20 0; #X connect 20 0 21 0; #X connect 21 0 22 0; #X restore 142 182 pd angleaxis2mtx; #X text 170 22 doesn't really work; #X msg 273 181 matrix 3 3 1 0 0 0 1 0 0 0 1; #X connect 0 0 1 0; #X connect 1 1 0 1; #X connect 2 0 6 0; #X connect 3 0 4 0; #X connect 4 0 0 0; #X connect 6 0 0 1; #X restore 485 276 pd angleaxis; #X obj 412 79 inlet; #X obj 51 237 wrap -180 180; #X obj 88 257 wrap -180 180; #X obj 125 277 wrap -180 180; #X connect 0 0 1 0; #X connect 1 0 3 0; #X connect 1 1 3 0; #X connect 3 0 5 0; #X connect 3 1 13 0; #X connect 3 2 14 0; #X connect 4 0 6 0; #X connect 5 0 17 0; #X connect 5 1 7 0; #X connect 7 0 12 0; #X connect 8 0 5 1; #X connect 8 1 13 1; #X connect 8 2 14 1; #X connect 9 0 8 0; #X connect 10 0 8 0; #X connect 11 0 10 0; #X connect 13 0 18 0; #X connect 13 1 7 1; #X connect 14 0 19 0; #X connect 14 1 7 2; #X connect 16 0 8 0; #X connect 17 0 4 0; #X connect 18 0 4 1; #X connect 19 0 4 2; wiimote-0.3.2/wiimote-help.pd0000644000175000017500000004776211432457065015162 0ustar romanroman#N struct IR-blobs float x float y symbol s; #N struct NC-stick float x float y; #N struct cc-left-stick float x float y; #N struct cc-right-stick float x float y; #N canvas 432 145 830 538 10; #X text 8 9 IN ORDER TO CONNECT: First put the wiimote into discover mode (press buttons 1 and 2 simultaneously).; #X text 16 364 You can also specify the address as a creation argument: ; #X text 15 380 (make sure to enable discover mode before creation) ; #X obj 435 5 cnv 15 375 460 empty empty Wiimote: 10 15 0 14 -261689 -143491 0; #X floatatom 577 159 7 0 0 1 _X #0-wii-accX-set #0-wii-accX; #X floatatom 577 173 7 0 0 1 _Y #0-wii-accY-set #0-wii-accY; #X floatatom 577 187 7 0 0 1 _Z #0-wii-accZ-set #0-wii-accZ; #X obj 447 159 hsl 128 14 -1 1 0 0 \$0-wii-accX \$0-wii-accX-set empty -2 -8 0 10 -204786 -1 -1 0 1; #X obj 447 173 hsl 128 14 -1 1 0 0 \$0-wii-accY \$0-wii-accY-set empty -2 -8 0 10 -204786 -1 -1 0 1; #X obj 447 187 hsl 128 14 -1 1 0 0 \$0-wii-accZ \$0-wii-accZ-set empty -2 -8 0 10 -204786 -1 -1 0 1; #N canvas 525 243 481 416 IR-data 0; #X scalar IR-blobs 128 384 blob1 \;; #X scalar IR-blobs 384 384 blob2 \;; #X scalar IR-blobs 640 384 blob3 \;; #X scalar IR-blobs 896 384 blob4 \;; #X coords 0 0 1024 768 256 196 1; #X restore 443 260 pd IR-data; #X text 444 242 IR Blobs (1024x768):; #X floatatom 577 207 7 0 0 1 _PITCH #0-wii-pitch-set #0-wii-pitch; #X obj 447 207 hsl 128 14 -3.14156 3.14159 0 0 \$0-wii-pitch \$0-wii-pitch-set empty -2 -8 0 10 -204786 -1 -1 0 1; #X floatatom 577 221 7 0 0 1 _ROLL #0-wii-roll-set #0-wii-roll; #X obj 447 221 hsl 128 14 -3.14156 3.14159 0 0 \$0-wii-roll \$0-wii-roll-set empty -2 -8 0 10 -204786 -1 -1 0 1; #X text 447 142 Acceleration (-1 to 1):; #X text 722 150 Buttons:; #X obj 15 427 print; #X obj 13 193 s \$0.to.wiimote; #X msg 28 121 discover; #X msg 13 74 connect 00:1F:C5:0B:1F:86; #X msg 39 164 disconnect; #X obj 500 36 tgl 25 0 empty empty IR 6 12 0 10 -4160 -1 -1 0 1; #X msg 500 90 report ir \$1; #X msg 441 69 report acceleration \$1; #X obj 441 35 tgl 25 0 empty empty Acc 4 12 0 10 -204786 -1 -1 0 1 ; #X obj 709 40 tgl 25 0 empty empty empty 17 7 0 10 -232576 -1 -1 0 1; #X msg 611 92 setLED \$1; #X obj 611 39 tgl 15 0 empty empty empty 17 7 0 10 -4032 -1 -1 0 1 ; #X obj 635 39 tgl 15 0 empty empty empty 17 7 0 10 -4032 -1 -1 0 1 ; #X obj 660 39 tgl 15 0 empty empty empty 17 7 0 10 -4032 -1 -1 0 1 ; #X obj 685 40 tgl 15 0 empty empty empty 17 7 0 10 -4032 -1 -1 0 1 ; #X text 606 15 LEDs:; #N canvas 0 0 409 401 bytemask 0; #X obj 269 332 outlet; #X obj 269 279 float; #X obj 318 183 |; #X obj 110 239 -; #X obj 110 204 float; #X obj 110 184 trigger bang float; #X obj 231 204 &; #X obj 183 142 route 0 1; #X msg 36 56 \$1 1; #X msg 106 56 \$1 2; #X msg 176 56 \$1 4; #X msg 246 56 \$1 8; #X obj 36 15 inlet; #X obj 106 15 inlet; #X obj 176 15 inlet; #X obj 246 15 inlet; #X obj 36 35 change; #X obj 106 35 change; #X obj 176 35 change; #X obj 246 35 change; #X connect 1 0 2 1; #X connect 1 0 4 1; #X connect 1 0 6 1; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 3 0 1 0; #X connect 4 0 3 0; #X connect 5 0 4 0; #X connect 5 1 6 0; #X connect 6 0 3 1; #X connect 7 0 5 0; #X connect 7 1 2 0; #X connect 8 0 7 0; #X connect 9 0 7 0; #X connect 10 0 7 0; #X connect 11 0 7 0; #X connect 12 0 16 0; #X connect 13 0 17 0; #X connect 14 0 18 0; #X connect 15 0 19 0; #X connect 16 0 8 0; #X connect 17 0 9 0; #X connect 18 0 10 0; #X connect 19 0 11 0; #X restore 611 69 pd bytemask; #X msg 709 91 setRumble \$1; #X obj 441 113 s \$0.to.wiimote; #X text 708 17 Rumble; #X obj 611 116 s \$0.to.wiimote; #N canvas 26 157 554 440 buttons 0; #X obj 11 11 r \$0.from.wiimote; #X obj 11 33 route button; #X obj 33 387 s \$0.button.up; #X obj 66 363 s \$0.button.down; #X obj 103 338 s \$0.button.left; #X obj 138 313 s \$0.button.right; #X obj 177 286 s \$0.button.a; #X obj 212 261 s \$0.button.b; #X obj 243 235 s \$0.button.minus; #X obj 280 208 s \$0.button.home; #X obj 325 180 s \$0.button.plus; #X obj 372 151 s \$0.button.1; #X obj 404 122 s \$0.button.2; #X obj 11 79 unpack f f; #X obj 11 56 list; #X obj 33 359 & 8; #X obj 66 335 & 4; #X obj 103 310 & 1; #X obj 138 285 & 2; #X obj 177 258 & 8; #X obj 212 233 & 4; #X obj 243 207 & 16; #X obj 280 180 & 128; #X obj 325 152 & 16; #X obj 372 123 & 2; #X obj 404 94 & 1; #X connect 0 0 1 0; #X connect 1 0 14 0; #X connect 13 0 15 0; #X connect 13 0 16 0; #X connect 13 0 17 0; #X connect 13 0 18 0; #X connect 13 0 23 0; #X connect 13 1 19 0; #X connect 13 1 20 0; #X connect 13 1 21 0; #X connect 13 1 22 0; #X connect 13 1 24 0; #X connect 13 1 25 0; #X connect 14 0 13 0; #X connect 15 0 2 0; #X connect 16 0 3 0; #X connect 17 0 4 0; #X connect 18 0 5 0; #X connect 19 0 6 0; #X connect 20 0 7 0; #X connect 21 0 8 0; #X connect 22 0 9 0; #X connect 23 0 10 0; #X connect 24 0 11 0; #X connect 25 0 12 0; #X restore 711 385 pd buttons; #N canvas 12 0 677 674 accel 0; #X obj 359 239 unpack 0 0 0; #X obj 92 612 expr sqrt(pow($f1 \, 2) + pow($f2 \, 2) + pow($f3 \, 2)); #X obj 350 298 atan; #X obj 350 277 expr $f1 / $f2; #X obj 383 322 expr if ($f1 > 0 \, 3.14159 \, -3.14159); #X obj 350 349 pack 0 0 0; #X obj 350 371 expr if ($f3 <= 0 \, $f1 + $f2 \, $f1); #X obj 350 393 * -1; #X obj 299 128 unpack 0 0 0; #X obj 35 461 s \$0-wii-pitch-set; #X obj 350 463 s \$0-wii-roll-set; #X obj 378 148 s \$0-wii-accZ-set; #X obj 338 167 s \$0-wii-accY-set; #X obj 299 186 s \$0-wii-accX-set; #X text 75 514 The pitch and roll are only accurate if there are no extra accelerations due to hand movement. We can check if the total acceleration is close to gravity and only use pitch and roll in that case. The total acceleration is given by:; #X text 311 106 raw accerlation:; #X obj 24 239 unpack 0 0 0; #X obj 35 298 atan; #X obj 35 277 expr $f1 / $f2; #X obj 67 322 expr if ($f1 > 0 \, 3.14159 \, -3.14159); #X obj 35 349 pack 0 0 0; #X obj 35 371 expr if ($f3 <= 0 \, $f1 + $f2 \, $f1); #X obj 35 393 * -1; #X obj 225 578 unpack 0 0 0; #X obj 126 71 t a; #X obj 126 20 r \$0.from.wiimote; #X obj 126 44 route acceleration; #X connect 0 0 3 0; #X connect 0 0 4 0; #X connect 0 2 3 1; #X connect 0 2 5 2; #X connect 2 0 5 0; #X connect 3 0 2 0; #X connect 4 0 5 1; #X connect 5 0 6 0; #X connect 6 0 7 0; #X connect 7 0 10 0; #X connect 8 0 13 0; #X connect 8 1 12 0; #X connect 8 2 11 0; #X connect 16 1 18 0; #X connect 16 1 19 0; #X connect 16 2 18 1; #X connect 16 2 20 2; #X connect 17 0 20 0; #X connect 18 0 17 0; #X connect 19 0 20 1; #X connect 20 0 21 0; #X connect 21 0 22 0; #X connect 22 0 9 0; #X connect 23 0 1 0; #X connect 23 1 1 1; #X connect 23 2 1 2; #X connect 24 0 8 0; #X connect 24 0 16 0; #X connect 24 0 0 0; #X connect 25 0 26 0; #X connect 26 0 24 0; #X restore 711 410 pd accel; #N canvas 195 75 568 473 ir 0; #N canvas 631 449 342 204 IR-blobs 0; #X obj 39 34 struct IR-blobs float x float y symbol s; #X obj 39 71 filledcurve 9 30 0 0 -30 -30 0 0 30 30 0; #X obj 48 112 drawsymbol s -60 -75 0 1 blob; #X restore 8 19 pd IR-blobs; #X obj 227 420 pointer; #X msg 227 398 traverse pd-IR-data \, next; #X obj 134 63 route 0 1 2 3; #X obj 134 422 unpack 0 0 0; #X obj 134 443 set IR-blobs x y; #X obj 245 350 pointer; #X obj 152 352 unpack 0 0 0; #X obj 152 373 set IR-blobs x y; #X msg 245 328 traverse pd-IR-data \, next \, next; #X obj 264 272 pointer; #X obj 171 266 unpack 0 0 0; #X obj 171 292 set IR-blobs x y; #X msg 264 250 traverse pd-IR-data \, next \, next \, next; #X obj 283 197 pointer; #X obj 190 199 unpack 0 0 0; #X obj 190 220 set IR-blobs x y; #X msg 283 175 traverse pd-IR-data \, next \, next \, next \, next ; #X obj 134 18 r \$0.from.wiimote; #X obj 134 40 route ir; #X msg 249 99 \$1 \$2 384 0; #X obj 249 40 t f f; #X obj 249 80 pack; #X msg 249 20 0 \, 1 \, 2 \, 3; #X obj 279 60 * 256; #X obj 279 80 + 128; #X obj 431 32 loadbang; #X obj 431 54 t b b; #X obj 228 147 t b b b b; #X connect 1 0 5 2; #X connect 2 0 1 0; #X connect 3 0 4 0; #X connect 3 1 7 0; #X connect 3 2 11 0; #X connect 3 3 15 0; #X connect 4 0 5 0; #X connect 4 1 5 1; #X connect 6 0 8 2; #X connect 7 0 8 0; #X connect 7 1 8 1; #X connect 9 0 6 0; #X connect 10 0 12 2; #X connect 11 0 12 0; #X connect 11 1 12 1; #X connect 13 0 10 0; #X connect 14 0 16 2; #X connect 15 0 16 0; #X connect 15 1 16 1; #X connect 17 0 14 0; #X connect 18 0 19 0; #X connect 19 0 3 0; #X connect 20 0 3 0; #X connect 21 0 22 0; #X connect 21 1 24 0; #X connect 22 0 20 0; #X connect 23 0 21 0; #X connect 24 0 25 0; #X connect 25 0 22 1; #X connect 26 0 27 0; #X connect 27 0 23 0; #X connect 27 1 28 0; #X connect 28 0 2 0; #X connect 28 1 9 0; #X connect 28 2 13 0; #X connect 28 3 17 0; #X restore 710 436 pd ir; #X obj 735 189 tgl 13 0 \$0.bli \$0.button.left empty 17 7 0 10 -191407 -1 -1 0 1; #X obj 763 189 tgl 13 0 \$0.bli \$0.button.right empty 17 7 0 10 -191407 -1 -1 0 2; #X obj 749 203 tgl 13 0 \$0.bli \$0.button.down empty 17 7 0 10 -191407 -1 -1 0 4; #X obj 749 175 tgl 13 0 \$0.bli \$0.button.up empty 17 7 0 10 -191407 -1 -1 0 8; #X obj 726 288 tgl 13 0 \$0.bli \$0.button.minus - 5 8 0 10 -191407 -1 -1 0 16; #X obj 750 288 tgl 13 0 \$0.bli \$0.button.home empty 17 7 0 10 -191407 -1 -1 0 128; #X obj 774 288 tgl 13 0 \$0.bli \$0.button.plus + 5 8 0 10 -191407 -1 -1 0 16; #X obj 747 228 tgl 18 0 \$0.bli \$0.button.b B 5 9 1 13 -191407 -1 -1 0 4; #X obj 747 240 tgl 18 0 \$0.bli \$0.button.a A 5 9 1 13 -191407 -1 -1 0 8; #X obj 749 322 tgl 16 0 \$0.bli \$0.button.1 1 5 9 1 11 -191407 -1 -1 0 2; #X obj 749 349 tgl 16 0 \$0.bli \$0.button.2 2 5 9 1 11 -191407 -1 -1 0 1; #X obj 215 317 spigot; #X obj 215 339 print WIIMOTE; #X obj 215 280 r \$0.from.wiimote; #X obj 254 299 tgl 15 0 empty empty print_data 19 7 0 13 -261234 -1 -1 0 1; #X obj 15 401 wiimote 00:1F:C5:0B:1F:86; #X text 10 221 By default \, the wiimote does not report acceleration data \, IR data \, or any data from an attached extension (eg \, nunchuck). You must specifically enable each reporting mode.; #X obj 16 279 cnv 15 140 70 empty empty empty 20 12 0 14 -228856 -66577 0; #X obj 21 305 wiimote; #X obj 21 283 r \$0.to.wiimote; #X obj 21 327 s \$0.from.wiimote; #X text 10 55 Then you can connect to a specific address:; #X text 27 103 Or you can try to automatically detect a wiimote:; #X obj 435 469 cnv 15 375 60 empty empty Extensions: 20 12 0 14 -204786 -66577 0; #N canvas 3 45 418 236 Nunchuck 0; #X obj 16 11 cnv 15 375 180 empty empty Nunchuk: 10 15 0 14 -228992 -355 0; #X floatatom 163 133 7 0 0 1 _X #0-nc-accX-set #0-nc-accX; #X floatatom 163 147 7 0 0 1 _Y #0-nc-accY-set #0-nc-accY; #X floatatom 163 161 7 0 0 1 _Z #0-nc-accZ-set #0-nc-accZ; #X obj 33 133 hsl 128 14 -1 1 0 0 \$0-nc-accX \$0-nc-accX-set empty -2 -8 0 10 -261681 -1 -1 0 1; #X obj 33 147 hsl 128 14 -1 1 0 0 \$0-nc-accY \$0-nc-accY-set empty -2 -8 0 10 -261681 -1 -1 0 1; #X obj 33 161 hsl 128 14 -1 1 0 0 \$0-nc-accZ \$0-nc-accZ-set empty -2 -8 0 10 -261681 -1 -1 0 1; #X obj 298 51 nbx 3 16 -1e+37 1e+37 0 0 empty \$0-nc-btn-set empty -80 8 0 10 -261681 -1 -1 0 256; #X text 29 117 Acceleration:; #X text 231 48 Buttons:; #X text 297 84 Stick:; #N canvas 185 133 481 416 NC-data 0; #X scalar NC-stick 130 133 \;; #X coords 0 0 256 256 80 80 1; #X restore 296 101 pd NC-data; #X obj 32 38 tgl 25 0 empty empty empty 17 7 0 10 -261682 -1 -1 0 1 ; #X msg 32 68 report nunchuk \$1; #X obj 32 89 s \$0.to.wiimote; #N canvas 3 217 743 313 nunchuk 0; #X obj 15 55 route button acceleration stick; #X obj 494 184 pointer; #X obj 494 141 loadbang; #X obj 387 153 unpack 0 0; #X obj 387 229 set NC-stick x y; #X obj 160 148 unpack 0 0 0; #X obj 240 169 s \$0-nc-accZ-set; #X obj 200 188 s \$0-nc-accY-set; #X obj 160 211 s \$0-nc-accX-set; #X obj 15 169 s \$0-nc-btn-set; #X msg 494 162 traverse pd-NC-data \, next; #X obj 15 11 r \$0.from.wiimote; #X obj 15 33 route nunchuk; #N canvas 154 209 610 221 NC-stick 0; #X obj 39 34 struct NC-stick float x float y; #X obj 44 71 filledpolygon 900 20 0 5 -5 0 -20 -5 -5 -20 0 -5 5 0 20 5 5 20 0; #X restore 386 262 pd NC-stick; #X connect 0 0 9 0; #X connect 0 1 5 0; #X connect 0 2 3 0; #X connect 1 0 4 2; #X connect 2 0 10 0; #X connect 3 0 4 0; #X connect 3 1 4 1; #X connect 5 0 8 0; #X connect 5 1 7 0; #X connect 5 2 6 0; #X connect 10 0 1 0; #X connect 11 0 12 0; #X connect 12 0 0 0; #X restore 180 89 pd nunchuk; #X connect 12 0 13 0; #X connect 13 0 14 0; #X restore 570 482 pd Nunchuck; #N canvas 161 144 450 300 MotionPlus 0; #X obj 56 55 cnv 15 375 160 empty empty MotionPlus: 10 15 0 14 -262130 -83269 0; #X obj 67 86 tgl 25 0 empty empty empty 17 7 0 10 -203904 -1 -1 0 1 ; #X msg 67 116 report motionplus \$1; #X obj 67 137 s \$0.to.wiimote; #X floatatom 198 165 7 0 0 1 _pitch #0-wii-mp-pitch-set #0-wii-mp-pitch ; #X floatatom 198 179 7 0 0 1 _roll #0-wii-mp-roll-set #0-wii-mp-roll ; #X obj 68 165 hsl 128 14 0 16000 0 0 \$0-wii-mp-pitch \$0-wii-mp-pitch-set empty -2 -8 0 10 -203904 -1 -1 0 1; #X obj 68 179 hsl 128 14 0 16000 0 0 \$0-wii-mp-roll \$0-wii-mp-roll-set empty -2 -8 0 10 -203904 -1 -1 0 1; #N canvas 0 0 308 266 motionplus 0; #X obj 8 51 route motionplus; #X obj 8 73 route angle_rate low_speed; #X obj 97 98 unpack f f f; #X obj 8 134 unpack f f f; #X obj 8 20 r \$0.from.wiimote; #X obj 8 209 s \$0-wii-mp-pitch-set; #X obj 48 187 s \$0-wii-mp-roll-set; #X obj 89 162 s \$0-wii-mp-yaw-set; #X connect 0 0 1 0; #X connect 1 0 3 0; #X connect 1 1 2 0; #X connect 3 0 5 0; #X connect 3 1 6 0; #X connect 3 2 7 0; #X connect 4 0 0 0; #X restore 279 116 pd motionplus; #X floatatom 198 193 7 0 0 1 _yaw #0-wii-mp-yaw-set #0-wii-mp-yaw; #X obj 68 193 hsl 128 14 0 16000 0 0 \$0-wii-mp-yaw \$0-wii-mp-yaw-set empty -2 -8 0 10 -203904 -1 -1 0 1; #X connect 1 0 2 0; #X connect 2 0 3 0; #X restore 570 502 pd MotionPlus; #N canvas 3 45 450 300 ClassicController 0; #X obj 17 21 cnv 15 375 260 empty empty ClassicController: 10 15 0 14 -204786 -13381 0; #X obj 38 140 tgl 14 0 \$0.bli \$0.cc.button.L empty 17 7 0 10 -228856 -1 -1 0 32; #X obj 52 140 nbx 2 14 -1e+37 1e+37 0 0 \$0.bli \$0.cc.analog.L empty 0 -8 0 10 -228856 -1 -1 0 256; #X obj 121 130 tgl 14 0 \$0.bli \$0.cc.button.zl empty 17 7 0 10 -228856 -1 -1 0 128; #X obj 291 140 tgl 14 0 \$0.bli \$0.cc.button.R empty 17 7 0 10 -228856 -1 -1 0 2; #X obj 305 140 nbx 2 14 -1e+37 1e+37 0 0 \$0.bli \$0.cc.analog.R empty 0 -8 0 10 -228856 -1 -1 0 256; #X obj 236 130 tgl 14 0 \$0.bli \$0.cc.button.zr empty 17 7 0 10 -228856 -1 -1 0 4; #X obj 61 184 tgl 14 0 \$0.bli \$0.cc.button.up empty 17 7 0 10 -228856 -1 -1 0 1; #X obj 80 203 tgl 14 0 \$0.bli \$0.cc.button.right empty 17 7 0 10 -228856 -1 -1 0 128; #X obj 42 203 tgl 14 0 \$0.bli \$0.cc.button.left empty 17 7 0 10 -228856 -1 -1 0 2; #X obj 61 222 tgl 14 0 \$0.bli \$0.cc.button.down empty 17 7 0 10 -228856 -1 -1 0 64; #X obj 153 182 tgl 13 0 \$0.bli \$0.cc.button.minus - 5 8 0 10 -228856 -1 -1 0 16; #X obj 177 182 tgl 13 0 \$0.bli \$0.cc.button.home empty 17 7 0 10 -228856 -1 -1 0 8; #X obj 201 182 tgl 13 0 \$0.bli \$0.cc.button.plus + 5 8 0 10 -228856 -1 -1 0 4; #X obj 300 181 tgl 16 0 \$0.bli \$0.cc.button.x x 5 8 0 10 -228856 -1 -1 0 8; #X obj 321 202 tgl 16 0 \$0.bli \$0.cc.button.a a 5 8 0 10 -228856 -1 -1 0 16; #X obj 279 202 tgl 16 0 \$0.bli \$0.cc.button.y y 5 8 0 10 -228856 -1 -1 0 32; #X obj 300 223 tgl 16 0 \$0.bli \$0.cc.button.b b 5 8 0 10 -228856 -1 -1 0 64; #X msg 28 80 report classic \$1; #X obj 28 50 tgl 25 0 empty empty empty 17 7 0 10 -228856 -1 -1 0 1 ; #X obj 28 103 s \$0.to.wiimote; #N canvas 99 0 677 676 classic 0; #X obj 9 11 r \$0.from.wiimote; #X obj 9 33 route classic; #X obj 9 55 route button right_stick left_stick left right; #X obj 9 215 unpack f f; #X obj 7 642 s \$0.cc.button.left; #X obj 38 621 s \$0.cc.button.right; #X obj 83 599 s \$0.cc.button.down; #X obj 120 577 s \$0.cc.button.up; #X obj 152 554 s \$0.cc.button.x; #X obj 183 533 s \$0.cc.button.y; #X obj 293 467 s \$0.cc.button.L; #X obj 331 445 s \$0.cc.button.zl; #X obj 378 423 s \$0.cc.button.zr; #X obj 409 402 s \$0.cc.button.R; #X obj 440 379 s \$0.cc.button.minus; #X obj 476 357 s \$0.cc.button.home; #X obj 507 336 s \$0.cc.button.plus; #X obj 7 620 & 2; #X obj 38 599 & 128; #X obj 120 555 & 1; #X obj 83 577 & 64; #X obj 152 532 & 8; #X obj 183 511 & 32; #X obj 219 489 & 64; #X obj 219 511 s \$0.cc.button.b; #X obj 256 489 s \$0.cc.button.a; #X obj 256 467 & 16; #X obj 293 445 & 32; #X obj 331 423 & 128; #X obj 378 401 & 4; #X obj 409 380 & 2; #X obj 440 357 & 16; #X obj 476 335 & 8; #X obj 507 314 & 4; #X obj 200 99 s \$0.cc.analog.L; #X obj 264 77 s \$0.cc.analog.R; #N canvas 0 0 456 304 left_stick 0; #X obj 132 150 pointer; #X obj 132 107 loadbang; #X obj 25 80 unpack 0 0; #X msg 132 128 traverse pd-cc.l \, next; #X obj 25 195 set cc-left-stick x y; #N canvas 302 445 610 221 cc-left-stick 0; #X obj 39 68 filledpolygon 900 20 0 5 -5 0 -20 -5 -5 -20 0 -5 5 0 20 5 5 20 0; #X obj 39 34 struct cc-left-stick float x float y; #X restore 24 228 pd cc-left-stick; #X obj 25 31 inlet; #X obj 92 105 * -1; #X obj 92 127 + 64; #X obj 25 153 * 2; #X obj 92 159 * 2; #X connect 0 0 4 2; #X connect 1 0 3 0; #X connect 2 0 9 0; #X connect 2 1 7 0; #X connect 3 0 0 0; #X connect 6 0 2 0; #X connect 7 0 8 0; #X connect 8 0 10 0; #X connect 9 0 4 0; #X connect 10 0 4 1; #X restore 136 131 pd left_stick; #N canvas 0 0 456 304 right_stick 0; #X obj 176 144 pointer; #X obj 177 101 loadbang; #X obj 25 79 unpack 0 0; #X obj 25 31 inlet; #X obj 92 104 * -1; #X msg 177 122 traverse pd-cc.r \, next; #X obj 25 192 set cc-right-stick x y; #N canvas 302 445 610 221 cc-right-stick 0; #X obj 39 68 filledpolygon 900 20 0 5 -5 0 -20 -5 -5 -20 0 -5 5 0 20 5 5 20 0; #X obj 39 34 struct cc-right-stick float x float y; #X restore 24 228 pd cc-right-stick; #X obj 92 126 + 32; #X obj 25 159 * 4; #X obj 92 157 * 4; #X connect 0 0 6 2; #X connect 1 0 5 0; #X connect 2 0 9 0; #X connect 2 1 4 0; #X connect 3 0 2 0; #X connect 4 0 8 0; #X connect 5 0 0 0; #X connect 8 0 10 0; #X connect 9 0 6 0; #X connect 10 0 6 1; #X restore 72 156 pd right_stick; #X connect 0 0 1 0; #X connect 1 0 2 0; #X connect 2 0 3 0; #X connect 2 1 37 0; #X connect 2 2 36 0; #X connect 2 3 34 0; #X connect 2 4 35 0; #X connect 3 0 20 0; #X connect 3 0 18 0; #X connect 3 0 27 0; #X connect 3 0 30 0; #X connect 3 0 31 0; #X connect 3 0 32 0; #X connect 3 0 33 0; #X connect 3 1 17 0; #X connect 3 1 19 0; #X connect 3 1 21 0; #X connect 3 1 22 0; #X connect 3 1 23 0; #X connect 3 1 26 0; #X connect 3 1 28 0; #X connect 3 1 29 0; #X connect 17 0 4 0; #X connect 18 0 5 0; #X connect 19 0 7 0; #X connect 20 0 6 0; #X connect 21 0 8 0; #X connect 22 0 9 0; #X connect 23 0 24 0; #X connect 26 0 25 0; #X connect 27 0 10 0; #X connect 28 0 11 0; #X connect 29 0 12 0; #X connect 30 0 13 0; #X connect 31 0 14 0; #X connect 32 0 15 0; #X connect 33 0 16 0; #X restore 238 69 pd classic; #N canvas 325 377 481 416 cc.l 0; #X scalar cc-left-stick 62 66 \;; #X coords 0 0 128 128 50 50 1; #X restore 121 215 pd cc.l; #N canvas 185 133 481 416 cc.r 0; #X scalar cc-right-stick 64 64 \;; #X coords 0 0 128 128 50 50 1; #X restore 203 214 pd cc.r; #X connect 18 0 20 0; #X connect 19 0 18 0; #X restore 667 482 pd ClassicController; #N canvas 203 133 450 300 Balance 0; #X obj 37 56 cnv 15 375 215 empty empty Balance: 10 15 0 14 -232576 -13381 0; #X obj 46 85 tgl 25 0 empty empty empty 17 7 0 10 -261234 -1 -1 0 1 ; #X obj 46 138 s \$0.to.wiimote; #X msg 46 115 report balance \$1; #N canvas 475 229 445 263 balance 0; #X obj 8 20 r \$0.from.wiimote; #X obj 8 51 route balance; #X obj 8 73 unpack; #X obj 8 95 s \$0-bal-X-set; #X obj 41 115 s \$0-bal-Y-set; #X connect 0 0 1 0; #X connect 1 0 2 0; #X connect 2 0 3 0; #X connect 2 1 4 0; #X restore 249 98 pd balance; #X text 228 144 ! Untested !; #X text 232 164 (but might work); #X floatatom 97 211 7 0 0 1 _X #0-bal-X-set #0-bal-X; #X floatatom 227 211 7 0 0 1 _Y #0-bal-Y-set #0-bal-Y; #X connect 1 0 3 0; #X connect 3 0 2 0; #X restore 667 502 pd Balance; #X text 18 472 (c) 2007-2010 Mike Wozniewski \, IOhannes m zmoelnig & Roman Haefeli; #X connect 20 0 19 0; #X connect 21 0 19 0; #X connect 22 0 19 0; #X connect 23 0 24 0; #X connect 24 0 36 0; #X connect 25 0 36 0; #X connect 26 0 25 0; #X connect 27 0 35 0; #X connect 28 0 38 0; #X connect 29 0 34 0; #X connect 30 0 34 1; #X connect 31 0 34 2; #X connect 32 0 34 3; #X connect 34 0 28 0; #X connect 35 0 38 0; #X connect 53 0 54 0; #X connect 55 0 53 0; #X connect 56 0 53 1; #X connect 57 0 18 0; #X connect 60 0 62 0; #X connect 61 0 60 0; #X coords 0 0 1 1 50 50 0; wiimote-0.3.2/Makefile0000644000175000017500000002411611437723350013654 0ustar romanroman## Pd library template version 1.0.2 # For instructions on how to use this template, see: # http://puredata.info/docs/developer/MakefileTemplate LIBRARY_NAME = wiimote # add your .c source files, one object per file, to the SOURCES # variable, help files will be included automatically SOURCES = wiimote.c # list all pd objects (i.e. myobject.pd) files here, and their helpfiles will # be included automatically #PDOBJECTS = # example patches and related files, in the 'examples' subfolder #EXAMPLES = # manuals and related files, in the 'manual' subfolder #MANUAL = # if you want to include any other files in the source and binary tarballs, # list them here. This can be anything from header files, test patches, # documentation, etc. README.txt and LICENSE.txt are required and therefore # automatically included EXTRA_DIST = #------------------------------------------------------------------------------# # # things you might need to edit if you are using other C libraries # #------------------------------------------------------------------------------# CFLAGS = -DPD -I$(PD_PATH)/src -Wall -W -g $(shell pkg-config --cflags cwiid) LDFLAGS = LIBS = $(shell pkg-config --libs cwiid) #------------------------------------------------------------------------------# # # you shouldn't need to edit anything below here, if we did it right :) # #------------------------------------------------------------------------------# # get library version from meta file LIBRARY_VERSION = $(shell sed -n 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' $(LIBRARY_NAME)-meta.pd) CFLAGS += -DVERSION='"$(LIBRARY_VERSION)"' # where Pd lives PD_PATH = ../../pd # where to install the library prefix = /usr/local libdir = $(prefix)/lib pkglibdir = $(libdir)/pd/extra objectsdir = $(pkglibdir) INSTALL = install INSTALL_FILE = $(INSTALL) -p -m 644 INSTALL_DIR = $(INSTALL) -p -m 755 -d ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \ $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows) DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION) ORIGDIR=pd-$(LIBRARY_NAME)_$(LIBRARY_VERSION) UNAME := $(shell uname -s) ifeq ($(UNAME),Darwin) CPU := $(shell uname -p) ifeq ($(CPU),arm) # iPhone/iPod Touch SOURCES += $(SOURCES_iphoneos) EXTENSION = pd_darwin OS = iphoneos IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin CC=$(IPHONE_BASE)/gcc CPP=$(IPHONE_BASE)/cpp CXX=$(IPHONE_BASE)/g++ ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6 OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer CFLAGS := $(IPHONE_CFLAGS) $(OPT_CFLAGS) $(CFLAGS) \ -I/Applications/Pd-extended.app/Contents/Resources/include LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT) LIBS += -lc STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) else # Mac OS X SOURCES += $(SOURCES_macosx) EXTENSION = pd_darwin OS = macosx OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast # build universal 32-bit on 10.4 and 32/64 on newer ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8) FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.4 else FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4 SOURCES += $(SOURCES_iphoneos) endif CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include \ -I/Applications/Pd-extended.app/Contents/Resources/include LDFLAGS += $(FAT_FLAGS) -bundle -undefined dynamic_lookup -L/sw/lib # if the 'pd' binary exists, check the linking against it to aid with stripping LDFLAGS += $(shell test -e $(PD_PATH)/bin/pd && echo -bundle_loader $(PD_PATH)/bin/pd) LIBS += -lc STRIP = strip -x DISTBINDIR=$(DISTDIR)-$(OS) # install into ~/Library/Pd on Mac OS X since /usr/local isn't used much pkglibdir=$(HOME)/Library/Pd endif endif ifeq ($(UNAME),Linux) CPU := $(shell uname -m) SOURCES += $(SOURCES_linux) EXTENSION = pd_linux OS = linux OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer CFLAGS += -fPIC LDFLAGS += -Wl,--export-dynamic -shared -fPIC LIBS += -lc STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_cygwin) EXTENSION = dll OS = cygwin OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer CFLAGS += LDFLAGS += -Wl,--export-dynamic -shared -L$(PD_PATH)/src LIBS += -lc -lpd STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif ifeq (MINGW,$(findstring MINGW,$(UNAME))) CPU := $(shell uname -m) SOURCES += $(SOURCES_windows) EXTENSION = dll OS = windows OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer -march=i686 -mtune=pentium4 CFLAGS += -mms-bitfields LDFLAGS += -s -shared -Wl,--enable-auto-import LIBS += -L$(PD_PATH)/src -L$(PD_PATH)/bin -L$(PD_PATH)/obj -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif # in case somebody manually set the HELPPATCHES above HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.c=-help.pd) CFLAGS += $(OPT_CFLAGS) .PHONY = install libdir_install single_install install-doc install-exec install-examples install-manual clean dist etags $(LIBRARY_NAME) all: $(SOURCES:.c=.$(EXTENSION)) %.o: %.c $(CC) $(CFLAGS) -o "$*.o" -c "$*.c" %.$(EXTENSION): %.o $(CC) $(LDFLAGS) -o "$*.$(EXTENSION)" "$*.o" $(LIBS) chmod a-x "$*.$(EXTENSION)" # this links everything into a single binary file $(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(CC) $(LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(LIBS) chmod a-x $(LIBRARY_NAME).$(EXTENSION) install: libdir_install # The meta and help files are explicitly installed to make sure they are # actually there. Those files are not optional, then need to be there. libdir_install: $(SOURCES:.c=.$(EXTENSION)) install-doc install-examples install-manual $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_FILE) $(LIBRARY_NAME)-meta.pd \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(SOURCES))" || (\ $(INSTALL_FILE) $(SOURCES:.c=.$(EXTENSION)) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) && \ $(STRIP) $(addprefix $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/,$(SOURCES:.c=.$(EXTENSION)))) test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_FILE) $(PDOBJECTS) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) # install library linked as single binary single_install: $(LIBRARY_NAME) install-doc install-exec $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_FILE) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION) install-doc: $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) test -z "$(strip $(SOURCES) $(PDOBJECTS))" || \ $(INSTALL_FILE) $(HELPPATCHES) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_FILE) README $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt $(INSTALL_FILE) LICENSE $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/LICENSE.txt install-examples: test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_FILE) examples/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples; \ done install-manual: test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual && \ for file in $(MANUAL); do \ $(INSTALL_FILE) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \ done clean: -rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o) -rm -f -- $(SOURCES:.c=.$(EXTENSION)) -rm -f -- $(LIBRARY_NAME).o -rm -f -- $(LIBRARY_NAME).$(EXTENSION) distclean: clean -rm -f -- $(DISTBINDIR).tar.gz -rm -rf -- $(DISTBINDIR) -rm -f -- $(DISTDIR).tar.gz -rm -rf -- $(DISTDIR) -rm -f -- $(ORIGDIR).tar.gz -rm -rf -- $(ORIGDIR) $(DISTBINDIR): $(INSTALL_DIR) $(DISTBINDIR) libdir: all $(DISTBINDIR) $(INSTALL_FILE) $(LIBRARY_NAME)-meta.pd $(DISTBINDIR) $(INSTALL_FILE) $(SOURCES) $(DISTBINDIR) $(INSTALL_FILE) $(HELPPATCHES) $(DISTBINDIR) test -z "$(strip $(EXTRA_DIST))" || \ $(INSTALL_FILE) $(EXTRA_DIST) $(DISTBINDIR) # tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR) $(DISTDIR): $(INSTALL_DIR) $(DISTDIR) $(ORIGDIR): $(INSTALL_DIR) $(ORIGDIR) dist: $(DISTDIR) $(INSTALL_FILE) Makefile $(DISTDIR) $(INSTALL_FILE) README.txt $(DISTDIR) $(INSTALL_FILE) LICENSE.txt $(DISTDIR) $(INSTALL_FILE) $(LIBRARY_NAME)-meta.pd $(DISTDIR) test -z "$(strip $(ALLSOURCES))" || \ $(INSTALL_FILE) $(ALLSOURCES) $(DISTDIR) test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_FILE) $(PDOBJECTS) $(DISTDIR) test -z "$(strip $(HELPPATCHES))" || \ $(INSTALL_FILE) $(HELPPATCHES) $(DISTDIR) test -z "$(strip $(EXTRA_DIST))" || \ $(INSTALL_FILE) $(EXTRA_DIST) $(DISTDIR) test -z "$(strip $(EXAMPLES))" || \ $(INSTALL_DIR) $(DISTDIR)/examples && \ for file in $(EXAMPLES); do \ $(INSTALL_FILE) examples/$$file $(DISTDIR)/examples; \ done test -z "$(strip $(MANUAL))" || \ $(INSTALL_DIR) $(DISTDIR)/manual && \ for file in $(MANUAL); do \ $(INSTALL_FILE) manual/$$file $(DISTDIR)/manual; \ done tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR) # make a Debian source package dpkg-source: debclean make distclean dist mv $(DISTDIR) $(ORIGDIR) tar --exclude-vcs -czpf ../$(ORIGDIR).orig.tar.gz $(ORIGDIR) rm -f -- $(DISTDIR).tar.gz rm -rf -- $(DISTDIR) $(ORIGDIR) cd .. && dpkg-source -b $(LIBRARY_NAME) etags: etags *.h $(SOURCES) ../../pd/src/*.[ch] /usr/include/*.h /usr/include/*/*.h showsetup: @echo "PD_PATH: $(PD_PATH)" @echo "objectsdir: $(objectsdir)" @echo "LIBRARY_NAME: $(LIBRARY_NAME)" @echo "LIBRARY_VERSION: $(LIBRARY_VERSION)" @echo "SOURCES: $(SOURCES)" @echo "PDOBJECTS: $(PDOBJECTS)" @echo "ALLSOURCES: $(ALLSOURCES)" @echo "UNAME: $(UNAME)" @echo "CPU: $(CPU)" @echo "pkglibdir: $(pkglibdir)" @echo "DISTDIR: $(DISTDIR)" @echo "ORIGDIR: $(ORIGDIR)" wiimote-0.3.2/wiimote.c0000644000175000017500000007711411432457065014045 0ustar romanroman// =================================================================== // Wiimote external for Puredata // Written by Mike Wozniewski (Feb 2007), www.mikewoz.com // // Requires the CWiid library (version 0.6.00) by L. Donnie Smith // // =================================================================== // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // =================================================================== // ChangeLog: // 2008-04-14 Florian Krebs // * adapt wiimote external for the actual version of cwiid (0.6.00) // 2009-09-14 IOhannes m zmölnig // * made it compile without private cwiid-headers #include #include #include #include #include #include #include #define PI 3.14159265358979323 // class and struct declarations for wiimote pd external: static t_class *wiimote_class; typedef struct _wiimote { t_object x_obj; // standard pd object (must be first in struct) cwiid_wiimote_t *wiimote; // individual wiimote handle per pd object, represented in libcwiid t_float connected; int wiimoteID; int reportMode; struct acc_cal acc_cal; /* calibration for built-in accelerometer */ #ifdef CWIID_RPT_NUNCHUK struct acc_cal nc_acc_cal; /* calibration for nunchuk accelerometer */ #endif #ifdef CWIID_RPT_BALANCE struct balance_cal balance_cal; #endif // outlets: t_outlet *outlet_data; t_outlet *outlet_status; struct timespec*basetime; double baselogicaltime; } t_wiimote; static t_clock*g_clock=NULL; typedef struct _wiimoteList { t_wiimote*x; int id; struct _wiimoteList*next; } t_wiimoteList; t_wiimoteList*g_wiimoteList=NULL; static int addWiimoteObject(t_wiimote*x, int id) { t_wiimoteList*wl=g_wiimoteList; t_wiimoteList*newentry=NULL; if(NULL!=wl) { while(wl->next) { if(wl->x == x) { pd_error(x, "[wiimote]: already bound to Wii%02d", wl->id); return 0; } if(wl->id == id) { pd_error(x, "[wiimote]: another object is already bound to Wii%02d", wl->id); return 0; } wl=wl->next; } } newentry=(t_wiimoteList*)getbytes(sizeof(t_wiimoteList)); newentry->next=NULL; newentry->x=x; newentry->id=id; if(wl) wl->next=newentry; else g_wiimoteList=newentry; return 1; } static t_wiimote*getWiimoteObject(const int id) { t_wiimoteList*wl=g_wiimoteList; if(NULL==wl) return NULL; while(wl) { if(id == wl->id) { return wl->x; } wl=wl->next; } return NULL; } static void removeWiimoteObject(const t_wiimote*x) { t_wiimoteList*wl=g_wiimoteList; t_wiimoteList*last=NULL; if(NULL==wl) return; while(wl) { if(x == wl->x) { if(last) { last->next=wl->next; } else { g_wiimoteList=wl->next; } wl->x=NULL; wl->id=0; wl->next=NULL; freebytes(wl, sizeof(t_wiimoteList)); return; } last=wl; wl=wl->next; } } /* time handling */ static void print_timestamp(struct timespec*timestamp, struct timespec*reference) { double t0=timestamp->tv_sec*1000. + (timestamp->tv_nsec) / 1000000.; double t1=0; double t=0; if(reference) { t1=reference->tv_sec*1000. + (reference->tv_nsec) / 1000000.; } t=t0-t1; post("timestamp: %f = %f-%f", (t), t0, t1); } static void wiimote_setbasetime(t_wiimote*x) { if(NULL==x->basetime) { x->basetime=(struct timespec*)getbytes(sizeof(struct timespec)); } if (clock_gettime(CLOCK_REALTIME, x->basetime)) { // oops freebytes(x->basetime, sizeof(struct timespec)); x->basetime=NULL; } x->baselogicaltime=clock_getlogicaltime(); } static double wiimote_timestamp2logicaltime(t_wiimote*x, struct timespec*timestamp) { double pddelay=clock_gettimesince(x->baselogicaltime); /* how long in logical time since we have connected to the wii */ double realdelay=0.; /* how long (in ms) after we connected to the wiimote this timestamp appeared */ double delay=0.; if(NULL==timestamp || NULL==x->basetime) return 0.; /* immediately */ realdelay= (timestamp->tv_sec - x->basetime->tv_sec) * 1000. + (timestamp->tv_nsec - x->basetime->tv_nsec) / 1000000.; delay=realdelay-pddelay; #if 0 print_timestamp(timestamp, x->basetime); post("logical time: %f = %f - %f", clock_gettimesince(x->baselogicaltime), now, x->baselogicaltime); #endif //post("diff = %f = %f - %f", realdelay-pddelay, realdelay, pddelay); if(delay<0) { return 0.; } return realdelay; } typedef struct _wiimoteMsgList { union cwiid_mesg*mesg; double timestamp; t_wiimote*x; struct _wiimoteMsgList*next; } t_wiimoteMsgList; t_wiimoteMsgList*g_wiimoteMsgList=NULL; static void addWiimsg(union cwiid_mesg mesg, double timestamp) { } // ============================================================== /* forward declarations */ static void wiimote_doDisconnect(t_wiimote *x); // ============================================================== static void wiimote_debug(t_wiimote *x) { post("\n======================"); if (x->connected) post("Wiimote (id: %d) is connected.", x->wiimoteID); else post("Wiimote (id: %d) is NOT connected.", x->wiimoteID); post("acceleration: %s", (x->reportMode & CWIID_RPT_ACC)?"ON":"OFF"); post("IR: %s", (x->reportMode & CWIID_RPT_IR)?"ON":"OFF"); post("extensions: %s", (x->reportMode & CWIID_RPT_EXT)?"ON":"OFF"); post(""); post("Accelerometer calibration: zero=(%d,%d,%d) one=(%d,%d,%d)", x->acc_cal.zero[CWIID_X], x->acc_cal.zero[CWIID_Y], x->acc_cal.zero[CWIID_Z], x->acc_cal.one [CWIID_X], x->acc_cal.one [CWIID_Y], x->acc_cal.one [CWIID_Z]); post("Nunchuk calibration: zero=(%d,%d,%d) one=(%d,%d,%d)", x->nc_acc_cal.zero[CWIID_X], x->nc_acc_cal.zero[CWIID_Y], x->nc_acc_cal.zero[CWIID_Z], x->nc_acc_cal.one [CWIID_X], x->nc_acc_cal.one [CWIID_Y], x->nc_acc_cal.one [CWIID_Z]); } // ============================================================== static void wiimote_out_status(t_wiimote *x, int state) { t_atom ap[1]; SETFLOAT(ap+0, state); outlet_anything(x->outlet_status, gensym("open"), 1, ap); } static void wiimote_cwiid_battery(t_wiimote *x, int battery) { t_atom ap[1]; t_float bat=(1.f*battery) / CWIID_BATTERY_MAX; SETFLOAT(ap+0, bat); outlet_anything(x->outlet_data, gensym("battery"), 1, ap); } // Button handler: static void wiimote_cwiid_btn(t_wiimote *x, struct cwiid_btn_mesg *mesg) { t_atom ap[2]; SETFLOAT(ap+0, (mesg->buttons & 0xFF00)>>8); SETFLOAT(ap+1, mesg->buttons & 0x00FF); outlet_anything(x->outlet_data, gensym("button"), 2, ap); } static void wiimote_cwiid_acc(t_wiimote *x, struct cwiid_acc_mesg *mesg) { double a_x, a_y, a_z; t_atom ap[3]; a_x = ((double)mesg->acc[CWIID_X] - x->acc_cal.zero[CWIID_X]) / (x->acc_cal.one[CWIID_X] - x->acc_cal.zero[CWIID_X]); a_y = ((double)mesg->acc[CWIID_Y] - x->acc_cal.zero[CWIID_Y]) / (x->acc_cal.one[CWIID_Y] - x->acc_cal.zero[CWIID_Y]); a_z = ((double)mesg->acc[CWIID_Z] - x->acc_cal.zero[CWIID_Z]) / (x->acc_cal.one[CWIID_Z] - x->acc_cal.zero[CWIID_Z]); /* double a, roll, pitch; a = sqrt(pow(a_x,2)+pow(a_y,2)+pow(a_z,2)); roll = atan(a_x/a_z); if (a_z <= 0.0) roll += PI * ((a_x > 0.0) ? 1 : -1); roll *= -1; pitch = atan(a_y/a_z*cos(roll)); */ SETFLOAT(ap+0, a_x); SETFLOAT(ap+1, a_y); SETFLOAT(ap+2, a_z); outlet_anything(x->outlet_data, gensym("acceleration"), 3, ap); } static void wiimote_cwiid_ir(t_wiimote *x, struct cwiid_ir_mesg *mesg) { unsigned int i; //post("IR (valid,x,y,size) #%d: %d %d %d %d", i, data->ir_data.ir_src[i].valid, data->ir_data.ir_src[i].x, data->ir_data.ir_src[i].y, data->ir_data.ir_src[i].size); for (i=0; isrc[i].valid) { t_atom ap[4]; SETFLOAT(ap+0, i); SETFLOAT(ap+1, mesg->src[i].pos[CWIID_X]); SETFLOAT(ap+2, mesg->src[i].pos[CWIID_Y]); SETFLOAT(ap+3, mesg->src[i].size); outlet_anything(x->outlet_data, gensym("ir"), 4, ap); } } } #ifdef CWIID_RPT_NUNCHUK static void wiimote_cwiid_nunchuk(t_wiimote *x, struct cwiid_nunchuk_mesg *mesg) { t_atom ap[4]; double a_x, a_y, a_z; a_x = ((double)mesg->acc[CWIID_X] - x->nc_acc_cal.zero[CWIID_X]) / (x->nc_acc_cal.one[CWIID_X] - x->nc_acc_cal.zero[CWIID_X]); a_y = ((double)mesg->acc[CWIID_Y] - x->nc_acc_cal.zero[CWIID_Y]) / (x->nc_acc_cal.one[CWIID_Y] - x->nc_acc_cal.zero[CWIID_Y]); a_z = ((double)mesg->acc[CWIID_Z] - x->nc_acc_cal.zero[CWIID_Z]) / (x->nc_acc_cal.one[CWIID_Z] - x->nc_acc_cal.zero[CWIID_Z]); /* double a, roll, pitch; a = sqrt(pow(a_x,2)+pow(a_y,2)+pow(a_z,2)); roll = atan(a_x/a_z); if (a_z <= 0.0) roll += PI * ((a_x > 0.0) ? 1 : -1); roll *= -1; pitch = atan(a_y/a_z*cos(roll)); */ if (mesg->buttons & CWIID_NUNCHUK_BTN_C) {} if (mesg->buttons & CWIID_NUNCHUK_BTN_Z) {} /* nunchuk button */ SETSYMBOL(ap+0, gensym("button")); SETFLOAT (ap+1, (t_float)mesg->buttons); outlet_anything(x->outlet_data, gensym("nunchuk"), 2, ap); /* nunchuk button */ SETSYMBOL(ap+0, gensym("acceleration")); SETFLOAT (ap+1, a_x); SETFLOAT (ap+2, a_y); SETFLOAT (ap+3, a_z); outlet_anything(x->outlet_data, gensym("nunchuk"), 4, ap); /* nunchuk button */ SETSYMBOL(ap+0, gensym("stick")); SETFLOAT (ap+1, mesg->stick[CWIID_X]); SETFLOAT (ap+2, mesg->stick[CWIID_Y]); outlet_anything(x->outlet_data, gensym("nunchuk"), 3, ap); } #endif #ifdef CWIID_RPT_CLASSIC static void wiimote_cwiid_classic(t_wiimote *x, struct cwiid_classic_mesg *mesg) { t_atom ap[3]; // t_float scale = 1.f / ((uint16_t)0xFFFF); SETSYMBOL(ap+0, gensym("left_stick")); SETFLOAT (ap+1, mesg->l_stick[CWIID_X]); SETFLOAT (ap+2, mesg->l_stick[CWIID_Y]); outlet_anything(x->outlet_data, gensym("classic"), 3, ap); SETSYMBOL(ap+0, gensym("right_stick")); SETFLOAT (ap+1, mesg->r_stick[CWIID_X]); SETFLOAT (ap+2, mesg->r_stick[CWIID_Y]); outlet_anything(x->outlet_data, gensym("classic"), 3, ap); SETSYMBOL(ap+0, gensym("left")); SETFLOAT (ap+1, mesg->l); outlet_anything(x->outlet_data, gensym("classic"), 2, ap); SETSYMBOL(ap+0, gensym("right")); SETFLOAT (ap+1, mesg->r); outlet_anything(x->outlet_data, gensym("classic"), 2, ap); SETSYMBOL(ap+0, gensym("button")); SETFLOAT(ap+1, (mesg->buttons & 0xFF00)>>8); SETFLOAT(ap+2, mesg->buttons & 0x00FF); outlet_anything(x->outlet_data, gensym("classic"), 3, ap); } #endif #ifdef CWIID_RPT_BALANCE #warning Balance ignores calibration data static void wiimote_cwiid_balance_output(t_wiimote *x, t_symbol*s, uint16_t value, uint16_t calibration[3]) { /* 1700 appears to be the step the calibrations are against. 17kg per sensor is 68kg, 1/2 of the advertised Japanese weight limit. */ #define WIIMOTE_BALANCE_CALWEIGHT 1700.f t_atom ap[2]; t_float weight=0; t_float falue=value; if(calibration) { if(valueoutlet_data, gensym("balance"), 2, ap); } static void wiimote_cwiid_balance(t_wiimote *x, struct cwiid_balance_mesg *mesg) { wiimote_cwiid_balance_output(x, gensym("right_top"), mesg->right_top, x->balance_cal.right_top); wiimote_cwiid_balance_output(x, gensym("right_bottom"), mesg->right_bottom, x->balance_cal.right_bottom); wiimote_cwiid_balance_output(x, gensym("left_top"), mesg->left_top, x->balance_cal.left_top); wiimote_cwiid_balance_output(x, gensym("left_bottom"), mesg->left_bottom, x->balance_cal.left_bottom); } #endif #ifdef CWIID_RPT_MOTIONPLUS static void wiimote_cwiid_motionplus(t_wiimote *x, struct cwiid_motionplus_mesg *mesg) { t_atom ap[4]; t_float scale = 1.f;// / ((uint16_t)0xFFFF); t_float phi = scale*mesg->angle_rate[CWIID_PHI]; t_float theta= scale*mesg->angle_rate[CWIID_THETA]; t_float psi = scale*mesg->angle_rate[CWIID_PSI]; t_float phi_speed = 1.; t_float theta_speed = 1.; t_float psi_speed = 1.; SETSYMBOL(ap+0, gensym("low_speed")); #ifdef HAVE_CWIID_MOTIONPLUS_LOWSPEED phi_speed = mesg->low_speed[CWIID_PHI]; theta_speed= mesg->low_speed[CWIID_THETA]; psi_speed = mesg->low_speed[CWIID_PSI]; #endif SETFLOAT (ap+1, phi_speed); SETFLOAT (ap+2, theta_speed); SETFLOAT (ap+3, psi_speed); outlet_anything(x->outlet_data, gensym("motionplus"), 4, ap); SETSYMBOL(ap+0, gensym("angle_rate")); SETFLOAT (ap+1, phi); SETFLOAT (ap+2, theta); SETFLOAT (ap+3, psi); outlet_anything(x->outlet_data, gensym("motionplus"), 4, ap); } #endif static void wiimote_cwiid_error(t_wiimote *x, struct cwiid_error_mesg *mesg) { switch(mesg->error) { case CWIID_ERROR_NONE: pd_error(x, "no error"); break; case CWIID_ERROR_DISCONNECT: pd_error(x, "disconnect error"); wiimote_doDisconnect(x); break; case CWIID_ERROR_COMM: pd_error(x, "comm error"); wiimote_doDisconnect(x); break; default: pd_error(x, "unknown error %d", mesg->error); } } static void wiimote_cwiid_message(t_wiimote *x, union cwiid_mesg*mesg) { if(NULL==x){ return; } if(NULL==mesg) { return; } switch (mesg->type) { case CWIID_MESG_STATUS: wiimote_cwiid_battery(x, mesg->status_mesg.battery); switch (mesg->status_mesg.ext_type) { case CWIID_EXT_NONE: verbose(1, "No extension attached"); break; #ifdef CWIID_RPT_NUNCHUK case CWIID_EXT_NUNCHUK: post("Nunchuk extension attached"); if(cwiid_get_acc_cal(x->wiimote, CWIID_EXT_NUNCHUK, &x->nc_acc_cal)) { post("Unable to retrieve nunchuk calibration"); } else { post("Retrieved nunchuk calibration: zero=(%02d,%02d,%02d) one=(%02d,%02d,%02d)", x->nc_acc_cal.zero[CWIID_X], x->nc_acc_cal.zero[CWIID_Y], x->nc_acc_cal.zero[CWIID_Z], x->nc_acc_cal.one [CWIID_X], x->nc_acc_cal.one [CWIID_Y], x->nc_acc_cal.one [CWIID_Z]); } break; #endif #ifdef CWIID_RPT_CLASSIC case CWIID_EXT_CLASSIC: post("Classic controller attached. There is no real support for this yet."); break; #endif #ifdef CWIID_RPT_BALANCE case CWIID_EXT_BALANCE: if(cwiid_get_balance_cal(x->wiimote, &x->balance_cal)) { post("Unable to retrieve balance calibration"); } break; #endif #ifdef CWIID_RPT_MOTIONPLUS case CWIID_EXT_MOTIONPLUS: post("MotionPlus controller attached."); /* no calibration needed for MotionPlus */ break; #endif case CWIID_EXT_UNKNOWN: post("Unknown extension attached"); break; default: post("ext mesg %d/%d unknown", mesg->type, mesg->status_mesg.ext_type); break; } break; case CWIID_MESG_BTN: wiimote_cwiid_btn(x, &mesg->btn_mesg); break; case CWIID_MESG_ACC: wiimote_cwiid_acc(x, &mesg->acc_mesg); break; case CWIID_MESG_IR: wiimote_cwiid_ir(x, &mesg->ir_mesg); break; #ifdef CWIID_RPT_NUNCHUK case CWIID_MESG_NUNCHUK: wiimote_cwiid_nunchuk(x, &mesg->nunchuk_mesg); break; #endif #ifdef CWIID_RPT_CLASSIC case CWIID_MESG_CLASSIC: wiimote_cwiid_classic(x, &mesg->classic_mesg); // todo break; #endif #ifdef CWIID_RPT_MOTIONPLUS case CWIID_MESG_MOTIONPLUS: wiimote_cwiid_motionplus(x, &mesg->motionplus_mesg); break; #endif #ifdef CWIID_RPT_BALANCE case CWIID_MESG_BALANCE: wiimote_cwiid_balance(x, &mesg->balance_mesg); break; #endif case CWIID_MESG_ERROR: wiimote_cwiid_error(x, &mesg->error_mesg); default: post("mesg %d unknown", (mesg->type)); break; } } #if 0 // queuing with sorted lists leads to "Mesg pipe overflow" static void wiimote_dequeue(void*nada) { /* get all the messages from the queue that are scheduled until now */ const int dyndelay=0; /* set this to 1 use dynamic delays for compensation of asynchronicity */ t_wiimoteMsgList*wl=g_wiimoteMsgList; t_wiimoteMsgList*next=NULL; double now=0; double nexttime=0.; if(NULL==wl) { /* no messages to dequeue; this should never happen */ } while(wl) { if(dyndelay) { now=clock_gettimesince(wl->x->baselogicaltime); if(now+1.timestamp) { /* no more messages to do for now, aborting */ break; } } next=wl->next; wiimote_cwiid_message(wl->x, wl->mesg); wl->x=NULL; wl->timestamp=0.; freebytes(wl->mesg, sizeof( union cwiid_mesg)); wl->mesg=NULL; wl->next=NULL; freebytes(wl, sizeof(t_wiimoteMsgList)); wl=next; } g_wiimoteMsgList=wl; /* reschedule clock */ if(dyndelay) { if(wl) { double delay=wl->timestamp - now; if(delay<1.)delay=1.; clock_delay(g_clock, delay); } } } static void wiimote_queue(t_wiimote*x, union cwiid_mesg*mesg, double timestamp) { /* add mesg to the queue with a Pd timestamp */ t_wiimoteMsgList*wl=g_wiimoteMsgList; t_wiimoteMsgList*lastentry=NULL; /* insert the current message into the list */ t_wiimoteMsgList*newentry=(t_wiimoteMsgList*)getbytes(sizeof(t_wiimoteMsgList)); newentry->next=NULL; newentry->x=x; newentry->mesg=(union cwiid_mesg*)getbytes(sizeof( union cwiid_mesg)); memcpy(newentry->mesg, mesg, (sizeof( union cwiid_mesg))); // post("queueing %x message %x (was %x) at %f", newentry, newentry->mesg, mesg, timestamp); newentry->timestamp=timestamp; if(NULL!=wl) { while(wl->next) { if(wl->timestamp>timestamp){ break; } lastentry=wl; wl=wl->next; } } if(lastentry) { newentry->next=lastentry->next; lastentry->next=newentry; } else { // at the beginning newentry->next=g_wiimoteMsgList; g_wiimoteMsgList=newentry; } /* reset the clock */ clock_delay(g_clock, 0); } #else static void wiimote_dequeue(void*nada) { /* flush all the messages from the queue */ t_wiimoteMsgList*wl=g_wiimoteMsgList; t_wiimoteMsgList*next=NULL; nada=NULL; /* ignore */ if(NULL==wl) { /* no messages to dequeue */ return; } while(wl) { next=wl->next; wiimote_cwiid_message(wl->x, wl->mesg); wl->x=NULL; wl->timestamp=0.; freebytes(wl->mesg, sizeof( union cwiid_mesg)); wl->mesg=NULL; wl->next=NULL; freebytes(wl, sizeof(t_wiimoteMsgList)); wl=next; } g_wiimoteMsgList=NULL; } static void wiimote_queue(t_wiimote*x, union cwiid_mesg*mesg, double timestamp) { /* add mesg to the queue with a Pd timestamp */ // t_wiimoteMsgList*wl=g_wiimoteMsgList; /* insert the current message into the list */ t_wiimoteMsgList*newentry=(t_wiimoteMsgList*)getbytes(sizeof(t_wiimoteMsgList)); newentry->next=g_wiimoteMsgList; newentry->x=x; newentry->mesg=(union cwiid_mesg*)getbytes(sizeof( union cwiid_mesg)); memcpy(newentry->mesg, mesg, (sizeof( union cwiid_mesg))); newentry->timestamp=timestamp; g_wiimoteMsgList=newentry; /* reset the clock */ clock_delay(g_clock, 0); } #endif static void cwiid_error_callback(cwiid_wiimote_t *wiimote, const char*err, va_list ap) { t_wiimote *x=NULL; if(g_wiimoteList==NULL||wiimote==NULL) { post("no wii's known"); return; } x=getWiimoteObject(cwiid_get_id(wiimote)); if(NULL==x) { if(err) { error("wiimote: %s", err); } else { error("wiimote: unknown error"); } } else { if(err) { pd_error(x, "wiimote: %s", err); } else { pd_error(x, "wiimote: unknown error"); } } } // The CWiid library invokes a callback function whenever events are // generated by the wiimote. This function is specified when connecting // to the wiimote (in the cwiid_open function). // Unfortunately, the mesg struct passed as an argument to the // callback does not have a pointer to the wiimote instance, and it // is thus impossible to know which wiimote-object has invoked the callback. // For this case we provide a hard-coded set of wrapper callbacks to // indicate which Pd wiimote instance to control. static void cwiid_callback(cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg_array[], struct timespec *timestamp) { int i; t_wiimote *x=NULL; double pd_timestamp=0; // print_timestamp(timestamp, NULL); if(g_wiimoteList==NULL||wiimote==NULL) { post("no wii's known"); return; } x=getWiimoteObject(cwiid_get_id(wiimote)); if(NULL==x) { post("no wiimote loaded: %d%",cwiid_get_id(wiimote)); return; } pd_timestamp=wiimote_timestamp2logicaltime(x, timestamp); sys_lock(); for (i=0; i < mesg_count; i++) { #if 1 wiimote_queue(x, mesg_array+i, pd_timestamp); #else wiimote_cwiid_message(x, mesg_array+i); #endif } sys_unlock(); } // ============================================================== static void wiimote_status(t_wiimote *x) { if(x->connected) { if (cwiid_request_status(x->wiimote)) { pd_error(x, "error requesting status message"); } } wiimote_out_status(x, x->connected); } static void wiimote_resetReportMode(t_wiimote *x) { if (x->connected) { verbose(1, "changing report mode for Wii%02d to %d", x->wiimoteID, x->reportMode); if (cwiid_command(x->wiimote, CWIID_CMD_RPT_MODE, x->reportMode)) { pd_error(x, "wiimote: could not set report mode."); } } } static void wiimote_setReportMode(t_wiimote *x, t_floatarg r) { if (r >= 0) { x->reportMode = (int) r; wiimote_resetReportMode(x); } else { return; } } static void wiimote_report(t_wiimote*x, t_symbol*s, int onoff) { int flag=-1; if(gensym("status")==s) flag=CWIID_RPT_STATUS; else if(gensym("button")==s) flag=CWIID_RPT_BTN; else if(gensym("acceleration")==s) flag=CWIID_RPT_ACC; else if(gensym("ir")==s) flag=CWIID_RPT_IR; #ifdef CWIID_RPT_NUNCHUK else if(gensym("nunchuk")==s) flag=CWIID_RPT_NUNCHUK; #endif #ifdef CWIID_RPT_CLASSIC else if(gensym("classic")==s) flag=CWIID_RPT_CLASSIC; #endif #ifdef CWIID_RPT_BALANCE else if(gensym("balance")==s) flag=CWIID_RPT_BALANCE; #endif #ifdef CWIID_RPT_MOTIONPLUS else if(gensym("motionplus")==s) flag=CWIID_RPT_MOTIONPLUS; #endif else if(gensym("ext")==s) flag=CWIID_RPT_EXT; else { pd_error(x, "unknown report mode '%s'", s->s_name); } #ifdef CWIID_RPT_MOTIONPLUS if(CWIID_RPT_MOTIONPLUS==flag) { if(x->connected) { int err=0; if(onoff) { err=cwiid_enable(x->wiimote, CWIID_FLAG_MOTIONPLUS); } else { err=cwiid_disable(x->wiimote, CWIID_FLAG_MOTIONPLUS); } if(err) { pd_error(x, "turning %s motionplus returned %d", (flag?"on":"off"), err); } } } #endif if(flag!=-1) { if(onoff) { x->reportMode |= flag; } else { x->reportMode &= ~flag; } } wiimote_resetReportMode(x); } static void wiimote_reportAcceleration(t_wiimote *x, t_floatarg f) { wiimote_report(x, gensym("acceleration"), f); } static void wiimote_reportIR(t_wiimote *x, t_floatarg f) { wiimote_report(x, gensym("ir"), f); } static void wiimote_reportNunchuk(t_wiimote *x, t_floatarg f) { wiimote_report(x, gensym("nunchuk"), f); } static void wiimote_reportMotionplus(t_wiimote *x, t_floatarg f) { wiimote_report(x, gensym("motionplus"), f); } static void wiimote_setRumble(t_wiimote *x, t_floatarg f) { if (x->connected) { if (cwiid_command(x->wiimote, CWIID_CMD_RUMBLE, f)) { pd_error(x, "wiimote: could not set rumble"); } } } static void wiimote_setLED(t_wiimote *x, t_floatarg f) { // some possible values: // CWIID_LED0_ON 0x01 // CWIID_LED1_ON 0x02 // CWIID_LED2_ON 0x04 // CWIID_LED3_ON 0x08 if (x->connected) { if (cwiid_command(x->wiimote, CWIID_CMD_LED, f)) { pd_error(x, "wiimote: could not set LED."); } } } // ============================================================== // The following function attempts to connect to a wiimote at a // specific address, provided as an argument. eg, 00:19:1D:70:CE:72 // This address can be discovered by running the following command // in a console: // hcitool scan | grep Nintendo static void wiimote_doConnect(t_wiimote *x, t_symbol *addr, t_symbol *dongaddr) { bdaddr_t bdaddr; unsigned int flags = CWIID_FLAG_MESG_IFC; bdaddr_t dong_bdaddr; bdaddr_t* dong_bdaddr_ptr=&dong_bdaddr; if(x->connected) { wiimote_doDisconnect(x); } // determine address: if (NULL==addr || addr==gensym("")) { verbose(1, "searching for wii..."); bdaddr = *BDADDR_ANY; } else { str2ba(addr->s_name, &bdaddr); verbose(1, "Connecting to Wii '%s'", addr->s_name); } post("Press buttons 1 and 2 simultaneously."); // determine dongleaddress: if (NULL==dongaddr || dongaddr==gensym("")) { verbose(1, "using default dongle"); dong_bdaddr_ptr = NULL; } else { verbose(1, "using dongle '%s'", dongaddr->s_name); str2ba(dongaddr->s_name, &dong_bdaddr); } // connect: #ifdef CWIID_OPEN_WITH_DONGLE verbose(1,"wiimote: opening multidongle"); x->wiimote = cwiid_open(&bdaddr, dong_bdaddr_ptr, flags); #else verbose(1,"wiimote: opening"); x->wiimote = cwiid_open(&bdaddr, flags); #endif if(NULL==x->wiimote) { pd_error(x, "wiimote: unable to connect"); wiimote_out_status(x, x->connected); return; } if(!addWiimoteObject(x, cwiid_get_id(x->wiimote))) { cwiid_close(x->wiimote); x->wiimote=NULL; wiimote_out_status(x, x->connected); return; } x->wiimoteID= cwiid_get_id(x->wiimote); post("wiimote %i is successfully connected", x->wiimoteID); if(cwiid_get_acc_cal(x->wiimote, CWIID_EXT_NONE, &x->acc_cal)) { post("Unable to retrieve accelerometer calibration"); } else { post("Retrieved wiimote calibration: zero=(%02d,%02d,%02d) one=(%02d,%02d,%02d)", x->acc_cal.zero[CWIID_X], x->acc_cal.zero[CWIID_Y], x->acc_cal.zero[CWIID_Z], x->acc_cal.one [CWIID_X], x->acc_cal.one [CWIID_Y], x->acc_cal.one [CWIID_Z]); } x->connected = 1; wiimote_out_status(x, x->connected); x->reportMode |= CWIID_RPT_STATUS; x->reportMode |= CWIID_RPT_BTN; wiimote_resetReportMode(x); if (cwiid_set_mesg_callback(x->wiimote, &cwiid_callback)) { pd_error(x, "Unable to set message callback"); } wiimote_setbasetime(x); } // The following function attempts to discover a wiimote. It requires // that the user puts the wiimote into 'discoverable' mode before being // called. This is done by pressing the red button under the battery // cover, or by pressing buttons 1 and 2 simultaneously. // TODO: Without pressing the buttons, I get a segmentation error. So far, I don't know why. static void wiimote_discover(t_wiimote *x) { post("Put the wiimote into discover mode by pressing buttons 1 and 2 simultaneously."); wiimote_doConnect(x, NULL, NULL); if (!(x->connected)) { pd_error(x, "could not find any wiimotes. Please ensure that bluetooth is enabled, and that the 'hcitool scan' command lists your Nintendo device."); } } static void wiimote_doDisconnect(t_wiimote *x) { if (x->connected) { if (cwiid_close(x->wiimote)) { pd_error(x, "wiimote: unable to close connection."); } else { post("disconnect successfull, resetting values"); removeWiimoteObject(x); x->connected = 0; } } else { post("device is not connected"); } wiimote_out_status(x, x->connected); } static void wiimote_bang(t_wiimote *x) { wiimote_out_status(x, x->connected); } // ============================================================== // ============================================================== static void *wiimote_new(t_symbol*s, int argc, t_atom *argv) { t_wiimote *x = (t_wiimote *)pd_new(wiimote_class); // create outlets: x->outlet_data = outlet_new(&x->x_obj, NULL); x->outlet_status = outlet_new(&x->x_obj, NULL); // initialize toggles: x->connected = 0; x->wiimoteID = -1; x->basetime=NULL; x->baselogicaltime=0.; // connect if user provided an address as an argument: if (argc==2) { post("[%s] connecting to provided address...", s->s_name); if (argv->a_type == A_SYMBOL) { wiimote_doConnect(x, NULL, atom_getsymbol(argv)); } else { error("[wiimote] expects either no argument, or a bluetooth address as an argument. eg, 00:19:1D:70:CE:72"); return NULL; } } return (x); } static void wiimote_free(t_wiimote* x) { wiimote_doDisconnect(x); /* cleanup the queue */ /* free the clock */ if(x->basetime) { freebytes(x->basetime, sizeof(struct timespec)); } if(x->outlet_data)outlet_free(x->outlet_data); x->outlet_data=NULL; if(x->outlet_status)outlet_free(x->outlet_status); x->outlet_status=NULL; } void wiimote_setup(void) { g_clock = clock_new(NULL, (t_method)wiimote_dequeue); if (cwiid_set_err(&cwiid_error_callback)) { error("wiimote: unable to set error callback"); } wiimote_class = class_new(gensym("wiimote"), (t_newmethod)wiimote_new, (t_method)wiimote_free, sizeof(t_wiimote), CLASS_DEFAULT, A_GIMME, 0); class_addmethod(wiimote_class, (t_method) wiimote_debug, gensym("debug"), 0); class_addmethod(wiimote_class, (t_method) wiimote_status, gensym("status"), 0); /* connection settings */ class_addmethod(wiimote_class, (t_method) wiimote_doConnect, gensym("connect"), A_DEFSYMBOL, A_DEFSYMBOL, 0); class_addmethod(wiimote_class, (t_method) wiimote_doDisconnect, gensym("disconnect"), 0); class_addmethod(wiimote_class, (t_method) wiimote_discover, gensym("discover"), 0); /* query data */ class_addbang(wiimote_class, (t_method) wiimote_bang); class_addmethod(wiimote_class, (t_method) wiimote_report, gensym("report"), A_SYMBOL, A_FLOAT, 0); class_addmethod(wiimote_class, (t_method) wiimote_setReportMode, gensym("setReportMode"), A_FLOAT, 0); class_addmethod(wiimote_class, (t_method) wiimote_reportAcceleration, gensym("reportAcceleration"), A_FLOAT, 0); class_addmethod(wiimote_class, (t_method) wiimote_reportIR, gensym("reportIR"), A_FLOAT, 0); class_addmethod(wiimote_class, (t_method) wiimote_reportNunchuk, gensym("reportNunchuck"), A_FLOAT, 0); class_addmethod(wiimote_class, (t_method) wiimote_reportNunchuk, gensym("reportNunchuk"), A_FLOAT, 0); class_addmethod(wiimote_class, (t_method) wiimote_reportMotionplus, gensym("reportMotionplus"), A_FLOAT, 0); /* set things on the wiimote */ class_addmethod(wiimote_class, (t_method) wiimote_setRumble, gensym("setRumble"), A_FLOAT, 0); class_addmethod(wiimote_class, (t_method) wiimote_setLED, gensym("setLED"), A_FLOAT, 0); post("[wiimote]: reading data from the Wii remote controller"); post(" (c) 2007 Mike Wozniewski"); post(" (c) 2008-2009 Florian Krebs"); post(" (c) 2009-2010 IOhannes m zmoelnig"); #ifdef VERSION post(" version " VERSION " published under the GNU General Public License"); #else post(" published under the GNU General Public License"); #endif } wiimote-0.3.2/LICENSE0000644000175000017500000004310311437671071013220 0ustar romanroman GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License.