[PD] problem making an audio-thread-safe external

Ivica Ico Bukvic ico.bukvic at gmail.com
Mon Oct 19 04:18:10 CEST 2009


OK,

So here's an implementation that apparently is as stable as it gets.
Basically, disconnect/connect had to remain where they are in order to
spawn callbacks within the main Pd thread. The three remaining
problematic messaging systems have been encapsulated into a single
thread (LED, Rumble, and SetReportMode). It appears to be pretty much
rock solid as far as stability is concerned with minimal CPU overhead.

Would something like this be acceptable or am I still missing something?

2 complaints about this implementation are:

1) connect brings pd to a screeching halt until either wiimote connects
or fails to do so (before in a threaded implementation this was not a
problem but had other issues, particularly with the callback running in
a separate thread, and also had issues by reporting "post" messages in a
different thread thus breaking compliance with Pd as pointed here
earlier). The rationale is you would want to do this before actually
performing hence it may be seen as passable. disconnect likewise drops
samples (albeit for a split second)

2) messaging from the other thread regarding problems with execution of
the three calls are currently commented out and as such users
potentially will never be notified of their occurrence. Any examples of
how this could be handled through a sys_lock or whatever it is, would be
most appreciated.

Best wishes,

Ico

On Sun, 2009-10-18 at 20:30 -0400, Ivica Ico Bukvic wrote:
> One small fix to the callback seem to have improved stability (now at
> least the thing loads and runs). The trick is when object is closed
> without explicitly disconnecting and loaded again and closed the same
> way (in both cases destructor ought to take care of things), the second
> time pd freezes. Closing object by clicking disconnect first and then
> closing the patch has no adverse effects.
> 
> Any ideas?
> 
> Also, as I learn more about pthreads, is the following a good/healthy
> approach to threaded design:
> 
> main wiimote/pd thread changes x->connection to a state that requests
> action from the manageConnections thread, which then in turn updates
> that state to something different. Since these are atomic changes and
> the code is to the best of my knowledge designed in such a way that only
> one of these can write to it at any given time (pd thread to change
> state but only if the manageConnections thread has finished its change
> of state, and manageConnections only changes its state when invoked
> during which time regular pd thread cannot access it).
> 
> Does this kind of design still require mutex implementation? Is this the
> source of instability?
> 
> Many thanks to all for your help in this matter!
> 
> Best wishes,
> 
> Ico
> 
> On Sun, 2009-10-18 at 20:22 -0400, Ivica Ico Bukvic wrote:
> > The problem is however that this is not the case. Whenever issuing
> > rumble/led commands and/or toggling various features (enable ir, acc,
> > nunchuk, etc.), cwiid call causes a dropout in audio thread. It's
> > obvious that the initial threaded implementation done by one of my
> > students should've been brought to closer scrutiny by myself (rather
> > than assuming it actually works). Now, that I've been messing with it
> > myself, I am learning a lot about pthreads and have arrived at an
> > implementation that might seem (at least to my own limited understanding
> > of pthreads) more feasible, except now I am getting random crashes and
> > instabilities.
> > 
> > The basic premise is to wrap select functionalities in separate threads
> > (e.g. rumble on/off) as follows:
> > 
> > the main struct wiimote has a variable that is set only through the main
> > Pd thread (via incoming messages), so that whenever a rumble on message
> > is requested, it sets this variable to 1 and when the rumble off is
> > requested, it sets this variable to 0.
> > 
> > Another thread is spawned at creation time with a while loop whose
> > variable is changed in free call (destructor) and whose thread is then
> > exited and joined with the main thread in the free call. This thread
> > also has usleep instruction to ensure that it does not hog CPU. Inside
> > the while loop (apart from the usleep) it monitors the aforesaid
> > variable in the main loop to see whether it has been changed (by
> > comparing it to an internal variable) and if so acts upon it. Once it
> > has acted upon it it adjusts its internal variable to match that of the
> > external rumble variable. this way at least theoretically one would not
> > have to deal with mutex stuff (or at least as far as I could gather),
> > yet the thing crashes left and right. Attached is the ugly hack of a
> > code I have so far.
> > 
> > Below is also code relevant to example cited above:
> > 
> > //this is the separate thread that is spawned at creation
> > //x->rumble is variable from the main wiimote struct that is not changed
> > //here but rather through external messages that call the function below
> > //in the free() function x->rumble is set to -1 and at that point
> > //pthread is joined before deleting the object
> > void cwiid_pthread_setRumble(void *ptr)
> > {
> > 	threadedFunctionParams *rPars = (threadedFunctionParams*)ptr;
> > 	t_wiimote *x = rPars->wiimote;
> > 	t_floatarg f = rPars->f;
> > 
> > 	while(x->rumble > -1) {
> > 		if (f != x->rumble) {
> > 			f = x->rumble;
> > 			if (cwiid_command(x->wiimote, CWIID_CMD_RUMBLE, f)) {
> > 				//post("wiiremote error: problem setting rumble.");
> > 			}
> > 		} else {
> > 			usleep(10000);
> > 		}
> > 	}
> > 	pthread_exit(0);
> > }
> > 
> > //this function is called when an external message arrives requesting
> > change in rumble status
> > void cwiid_setRumble(t_wiimote *x, t_floatarg f)
> > {
> > 	if (x->connected) {
> > 		x->rumble = f;
> > 	}
> > }
> > 
> > Any help in this is most appreciated.
> > 
> > Best wishes,
> > 
> > Ico
> > 
> > On Sun, 2009-10-18 at 17:04 -0400, Hans-Christoph Steiner wrote:
> > > I think a thread is likely just going to add complication here.  The  
> > > HID stuff is all without threads and works well.  If cwiid is already  
> > > threaded, then chances are you should be able to get data from its  
> > > threads using non-blocking calls.  If it already buffers the data,  
> > > then you don't need your own thread, just get the data from cwiid's  
> > > buffer in a non-blocking way.
> > > 
> > > This is how the Linux input API works, IIRC.
> > > 
> > > .hc
> > > 
> > > On Oct 17, 2009, at 10:33 PM, Ivica Ico Bukvic wrote:
> > > 
> > > > Hi all,
> > > >
> > > > I am currently working on a threaded implementation of a wiimote
> > > > external. The reason I was hoping threaded design would help is to  
> > > > avoid
> > > > dropped samples when issuing commands to wiimote (e.g. rumble/led  
> > > > status
> > > > change). So far, it seems that reading from wiimote, no matter how  
> > > > fast,
> > > > has no impact on the audio thread. However, writing even when such
> > > > action is generated through a separate thread seems to cause drop-outs
> > > > in the audio thread. The external (which was not originally built by  
> > > > me)
> > > > uses cwiid to communicate with wiimotes and my understanding is that
> > > > cwiid is heavily threaded in and of itself. An example of a threaded
> > > > code is below:
> > > >
> > > > void *cwiid_pthread2_setRumble(void *ptr)
> > > > {
> > > > 	
> > > > 	threadedFunctionParams *rPars = (threadedFunctionParams*)ptr;
> > > > 	t_wiimote *x = rPars->wiimote;
> > > > 	t_floatarg f = rPars->f;
> > > >
> > > > 	if (x->connected)
> > > > 	{
> > > > 		if (cwiid_command(x->wiimote, CWIID_CMD_RUMBLE, f)) post("wiiremote
> > > > error: problem setting rumble.");
> > > > 	}
> > > > }
> > > >
> > > > void cwiid_pthread_setRumble(t_wiimote *x, t_floatarg f)
> > > > {
> > > > 	threadedFunctionParams rPars;
> > > > 	rPars.wiimote = x;
> > > > 	rPars.f = f;
> > > > 	
> > > > 	pthread_t thread;
> > > > 	int iret1;
> > > >
> > > > 	iret1 = pthread_create( &thread, NULL, cwiid_pthread2_setRumble,
> > > > (void*) &rPars);
> > > > 	pthread_join(thread, NULL);
> > > > }
> > > >
> > > > So, cwiid_pthread_setRumble is called from Pd and then it in turn
> > > > creates a thread that sends info to cwiid library against which the
> > > > external is linked. I am confused as to why the new thread once it has
> > > > been created still affects the Pd's audio thread. Any ideas?
> > > >
> > > > Best wishes,
> > > >
> > > > Ico
> > > >
> > > >
> > > >
> > > >
> > > > _______________________________________________
> > > > Pd-list at iem.at mailing list
> > > > UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
> > > 
> > > 
> > > 
> > > ----------------------------------------------------------------------------
> > > 
> > > "[W]e have invented the technology to eliminate scarcity, but we are  
> > > deliberately throwing it away to benefit those who profit from  
> > > scarcity."        -John Gilmore
> > > 
> > > 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: disis_wiimote.c
Type: text/x-csrc
Size: 19839 bytes
Desc: not available
URL: <http://lists.puredata.info/pipermail/pd-list/attachments/20091018/4bc99fd8/attachment.c>
-------------- next part --------------
#N struct IR-blobs float x float y symbol s;
#N struct NC-stick float x float y symbol s;
#N canvas 123 47 881 512 10;
#X msg 6 388 disconnect;
#X obj 350 266 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X msg 60 95 discover;
#X msg 350 296 setRumble \$1;
#X obj 216 186 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 122 186 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X msg 216 216 reportAcceleration \$1;
#X msg 122 216 reportIR \$1;
#N canvas 25 33 700 644 \$0-accelerometer-stuff 0;
#X obj 218 12 inlet;
#X obj 366 221 unpack 0 0 0;
#X obj 92 612 expr sqrt(pow($f1 \, 2) + pow($f2 \, 2) + pow($f3 \,
2));
#X obj 357 280 atan;
#X obj 357 259 expr $f1 / $f2;
#X obj 389 304 expr if ($f1 > 0 \, 3.14159 \, -3.14159);
#X obj 357 331 pack 0 0 0;
#X obj 357 353 expr if ($f3 <= 0 \, $f1 + $f2 \, $f1);
#X obj 357 375 * -1;
#X obj 328 61 unpack 0 0 0;
#X obj 42 443 s \$0-wii-pitch-set;
#X obj 357 445 s \$0-wii-roll-set;
#X obj 407 81 s \$0-wii-accZ-set;
#X obj 367 100 s \$0-wii-accY-set;
#X obj 328 119 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 340 39 raw accerlation:;
#X obj 31 221 unpack 0 0 0;
#X obj 42 280 atan;
#X obj 42 259 expr $f1 / $f2;
#X obj 74 304 expr if ($f1 > 0 \, 3.14159 \, -3.14159);
#X obj 42 331 pack 0 0 0;
#X obj 42 353 expr if ($f3 <= 0 \, $f1 + $f2 \, $f1);
#X obj 42 375 * -1;
#X obj 225 578 unpack 0 0 0;
#X connect 0 0 9 0;
#X connect 0 0 17 0;
#X connect 0 0 1 0;
#X connect 1 0 4 0;
#X connect 1 0 5 0;
#X connect 1 2 4 1;
#X connect 1 2 6 2;
#X connect 3 0 6 0;
#X connect 4 0 3 0;
#X connect 5 0 6 1;
#X connect 6 0 7 0;
#X connect 7 0 8 0;
#X connect 8 0 11 0;
#X connect 9 0 14 0;
#X connect 9 1 13 0;
#X connect 9 2 12 0;
#X connect 17 1 19 0;
#X connect 17 1 20 0;
#X connect 17 2 19 1;
#X connect 17 2 21 2;
#X connect 18 0 21 0;
#X connect 19 0 18 0;
#X connect 20 0 21 1;
#X connect 21 0 22 0;
#X connect 22 0 23 0;
#X connect 23 0 10 0;
#X connect 24 0 2 0;
#X connect 24 1 2 1;
#X connect 24 2 2 2;
#X restore 86 472 pd \$0-accelerometer-stuff;
#N canvas 0 0 652 563 \$0-IR-stuff 0;
#X obj 134 18 inlet;
#X obj 122 510 pointer;
#X msg 122 488 traverse pd-IR-data \, next;
#X obj 134 63 route 0 1 2 3;
#X obj 23 482 unpack 0 0 0;
#X floatatom 483 44 5 0 0 0 IR-Blob: - -;
#X floatatom 522 44 5 0 0 0 - - -;
#X floatatom 562 44 5 0 0 0 - - -;
#X obj 15 533 set IR-blobs x y;
#X obj 231 400 pointer;
#X obj 132 372 unpack 0 0 0;
#X obj 124 423 set IR-blobs x y;
#X msg 231 378 traverse pd-IR-data \, next \, next;
#X obj 231 357 loadbang;
#X obj 122 467 loadbang;
#X obj 320 289 pointer;
#X obj 221 261 unpack 0 0 0;
#X obj 213 312 set IR-blobs x y;
#X obj 320 246 loadbang;
#X msg 320 267 traverse pd-IR-data \, next \, next \, next;
#X obj 380 177 pointer;
#X obj 281 149 unpack 0 0 0;
#X obj 273 200 set IR-blobs x y;
#X obj 380 134 loadbang;
#X msg 380 155 traverse pd-IR-data \, next \, next \, next \, next
;
#X connect 0 0 3 0;
#X connect 1 0 8 2;
#X connect 2 0 1 0;
#X connect 3 0 4 0;
#X connect 3 1 10 0;
#X connect 3 2 16 0;
#X connect 3 3 21 0;
#X connect 4 0 8 0;
#X connect 4 1 8 1;
#X connect 9 0 11 2;
#X connect 10 0 11 0;
#X connect 10 1 11 1;
#X connect 12 0 9 0;
#X connect 13 0 12 0;
#X connect 14 0 2 0;
#X connect 15 0 17 2;
#X connect 16 0 17 0;
#X connect 16 1 17 1;
#X connect 18 0 19 0;
#X connect 19 0 15 0;
#X connect 20 0 22 2;
#X connect 21 0 22 0;
#X connect 21 1 22 1;
#X connect 23 0 24 0;
#X connect 24 0 20 0;
#X restore 106 451 pd \$0-IR-stuff;
#X msg 478 313 setLED \$1;
#X obj 478 264 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 502 264 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 526 264 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 550 264 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X text 435 263 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 478 290 pd bytemask;
#X text 5 6 IN ORDER TO CONNECT: First put the wiimote into discover
mode (press buttons 1 and 2 simultaneously).;
#X text 221 68 <- Then you can connect to a specific address;
#X text 127 96 <- Or you can try to automatically detect a wiimote.
;
#X obj 375 186 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X text 74 557 You can also specify the address as a creation argument:
;
#X text 115 138 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 text 86 571 (make sure to enable discover mode before creation)
;
#X msg 375 216 reportNunchuck \$1;
#N canvas 0 0 920 244 \$0-nunchuck-stuff 0;
#X obj 559 61 inlet;
#X obj 672 134 pointer;
#X obj 672 91 loadbang;
#X obj 559 96 unpack 0 0;
#X obj 565 179 set NC-stick x y;
#X obj 49 71 inlet;
#X text 42 32 inlet #1: BUTTONS;
#X text 294 35 inlet #2: ACCELERATION;
#X obj 304 72 inlet;
#X obj 304 105 unpack 0 0 0;
#X obj 383 125 s \$0-nc-accZ-set;
#X obj 343 144 s \$0-nc-accY-set;
#X obj 304 163 s \$0-nc-accX-set;
#X text 567 32 inlet #3: STICK;
#X obj 49 117 s \$0-nc-btn-set;
#X msg 672 112 traverse pd-NC-data \, next;
#X connect 0 0 3 0;
#X connect 1 0 4 2;
#X connect 2 0 15 0;
#X connect 3 0 4 0;
#X connect 3 1 4 1;
#X connect 5 0 14 0;
#X connect 8 0 9 0;
#X connect 9 0 12 0;
#X connect 9 1 11 0;
#X connect 9 2 10 0;
#X connect 15 0 1 0;
#X restore 127 430 pd \$0-nunchuck-stuff;
#X obj 579 406 cnv 15 275 230 empty empty Nunchuk: 10 15 0 14 -228992
-355 0;
#X floatatom 756 470 7 0 0 1 _X #0-nc-accX-set #0-nc-accX;
#X floatatom 756 484 7 0 0 1 _Y #0-nc-accY-set #0-nc-accY;
#X floatatom 756 498 7 0 0 1 _Z #0-nc-accZ-set #0-nc-accZ;
#X obj 626 470 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 626 484 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 626 498 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 792 429 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 622 454 Acceleration:;
#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 681 614 pd NC-stick;
#X text 783 411 Buttons:;
#X text 698 518 Stick:;
#X obj 579 5 cnv 15 275 400 empty empty Wiimote: 10 15 0 14 -261689
-143491 0;
#X floatatom 742 80 7 0 0 1 _X #0-wii-accX-set #0-wii-accX;
#X floatatom 742 94 7 0 0 1 _Y #0-wii-accY-set #0-wii-accY;
#X floatatom 742 108 7 0 0 1 _Z #0-wii-accZ-set #0-wii-accZ;
#X obj 612 80 hsl 128 14 -1 1 0 0 \$0-wii-accX \$0-wii-accX-set empty
-2 -8 0 10 -225271 -1 -1 0 1;
#X obj 612 94 hsl 128 14 -1 1 0 0 \$0-wii-accY \$0-wii-accY-set empty
-2 -8 0 10 -225271 -1 -1 0 1;
#X obj 612 108 hsl 128 14 -1 1 0 0 \$0-wii-accZ \$0-wii-accZ-set empty
-2 -8 0 10 -225271 -1 -1 0 1;
#N canvas 525 243 481 416 IR-data 0;
#X scalar IR-blobs 909 63 blob1 \;;
#X scalar IR-blobs 250.25 49 blob2 \;;
#X scalar IR-blobs 145.5 182.25 blob3 \;;
#X scalar IR-blobs 491.008 468.615 blob4 \;;
#X coords 0 0 1024 768 256 196 1;
#X restore 590 183 pd IR-data;
#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 767 379 pd IR-blobs;
#X text 648 166 IR Blobs (1024x768):;
#X floatatom 742 128 7 0 0 1 _PITCH #0-wii-pitch-set #0-wii-pitch;
#X obj 612 128 hsl 128 14 -3.14156 3.14159 0 0 \$0-wii-pitch \$0-wii-pitch-set
empty -2 -8 0 10 -225280 -1 -1 0 1;
#X floatatom 742 142 7 0 0 1 _ROLL #0-wii-roll-set #0-wii-roll;
#X obj 612 142 hsl 128 14 -3.14156 3.14159 0 0 \$0-wii-roll \$0-wii-roll-set
empty -2 -8 0 10 -225280 -1 -1 0 1;
#X text 608 64 Acceleration (-1 to 1):;
#X obj 779 23 nbx 2 16 -1e+37 1e+37 0 0 empty \$0-wii-btn01-set empty
-100 10 0 12 -225280 -1 -1 0 256;
#X obj 814 23 nbx 2 16 -1e+37 1e+37 0 0 empty \$0-wii-btn02-set empty
0 10 0 12 -225280 -1 -1 0 256;
#N canvas 0 0 330 216 \$0-button-stuff 0;
#X obj 41 33 inlet;
#X obj 41 86 unpack 0 0;
#X obj 41 140 s \$0-wii-btn01-set;
#X obj 106 120 s \$0-wii-btn02-set;
#X connect 0 0 1 0;
#X connect 1 0 2 0;
#X connect 1 1 3 0;
#X restore 60 492 pd \$0-button-stuff;
#X text 783 5 Buttons:;
#N canvas 185 133 481 416 NC-data 0;
#X scalar NC-stick 135 130  \;;
#X coords 0 0 256 256 80 80 1;
#X restore 681 534 pd NC-data;
#X obj 161 615 print;
#X msg 36 73 connect 00:1E:35:1D:0E:15;
#X obj 15 233 metro 100;
#X obj 15 203 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X text 37 251 Enable metro to get accelerometer uppdates;
#X text 38 276 Buttons do not require bang to be updated;
#X text 5 36 Threaded implementation of Wiimote by DISIS <http://disis.music.vt.edu>
;
#X msg 306 394 mode \$1;
#X obj 306 364 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X text 304 425 0 (default) uses metro to initiate output;
#X text 304 437 1 outputs as fast as possible;
#X text 304 451 NB: buttons are independent from either;
#X text 304 411 mode of operation:;
#X text 328 462 mode offering highest resolution possible;
#X text 304 475 P.S. Running metro in mode 1;
#X text 333 486 is pretty much pointless;
#X obj 117 365 disis_wiimote;
#X obj 161 589 disis_wiimote 00:19:1D:BE:6A:66;
#X obj 250 364 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X text 231 388 connection;
#X text 236 398 indicator;
#X msg 6 366 debug;
#X text 39 286 since they have a much lower throughput.;
#X text 37 262 (xyz wiimote \, xyz nunchuk \, ir).;
#X text 39 301 NB: setting metro below 20 makes little sense;
#X text 39 311 as even at max rate I was unable to get more;
#X text 39 321 than 50 updates/second. The separate thread;
#X text 39 331 therefore has usleep of 10ms between updates.;
#X connect 0 0 74 0;
#X connect 1 0 3 0;
#X connect 2 0 74 0;
#X connect 3 0 74 0;
#X connect 4 0 6 0;
#X connect 5 0 7 0;
#X connect 6 0 74 0;
#X connect 7 0 74 0;
#X connect 10 0 74 0;
#X connect 11 0 16 0;
#X connect 12 0 16 1;
#X connect 13 0 16 2;
#X connect 14 0 16 3;
#X connect 16 0 10 0;
#X connect 20 0 24 0;
#X connect 24 0 74 0;
#X connect 59 0 74 0;
#X connect 60 0 74 0;
#X connect 61 0 60 0;
#X connect 65 0 74 0;
#X connect 66 0 65 0;
#X connect 74 0 55 0;
#X connect 74 1 8 0;
#X connect 74 2 9 0;
#X connect 74 3 25 0;
#X connect 74 4 25 1;
#X connect 74 5 25 2;
#X connect 74 6 76 0;
#X connect 75 0 58 0;
#X connect 79 0 74 0;


More information about the Pd-list mailing list