[PD] [flext] Inheriting access to variables declared once in a library

Christian Frisson theremin at free.fr
Tue Aug 1 07:59:35 CEST 2006


Re-,

More about the project: I'm trying to wrap a GPL C++ haptik API called the
Haptik Library (http://www.haptiklibrary.org) in a library of flext externals
in order to sense/actuate haptic devices directly under Pd/MSP. First attemps
have been made with Pd under Windows XP (Linux will follow), compiling with
nmake from VC++7 and debugging with a SensAble PHANToM Omni haptic device.
Basically a morph between the library example from the flext tutorial and the
"HelloHaptikConsole" example from the Haptik Library.

I hope you won't mind my pasting the code deliberately on the body of the
message (see below for the "ugly static" version), as I want to wait for a
proper first release before setting up a webpage.

I've tried to move the "static" variables as private members of the base flext
class and create protected accessors, but the compilation ended as a link error
(I'll paste the number ID on the next message).

On the list of yet unhandled important issues:
* the "m_signal" functions are not in sync with the frequency rate of the haptic
device;
* both "m_signal" instances seems to crosstalk, as they behave normally alone,
but not together, the following quotation of the Pd C external howto initiating
the answer:

"Optimization of the DSP-tree tries to avoid unnecessary copy-operations.
Therefore it is possible, that in- and out-signal are located at the same
address in the memory. In this case, the programmer has to be careful not to
write into the out-signal before having read the in-signal to avoid overwriting
data that is not yet saved."

Thanks for your previous realtime answer and beforehand for the one to come!
Christian

/*
-------------------------------------------------------------------------
haptik~ - the Haptik Library wrapped as a library of flext externals
Copyright (c) 2006 Christian Frisson
To be released under a GPL license
-------------------------------------------------------------------------
*/

// include flext header

#include <flext.h>



// check for appropriate flext version

#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 400)

#error You need at least flext version 0.4.0

#endif



// include Haptik headers

#include <windows.h>

#include <conio.h>

#include <stdio.h>

#include <RSLib\Haptik.hpp>

using namespace RSLib;

using namespace RSLib::Math;



Haptik haptikWrapper;

IHaptikDeviceInterface hapticDevice;

bool haptikDeviceStatus;

UINT32 haptikID, haptikRate, uRes;

HaptikData fdata, pdata;



//-----------------------------------------------------------------------

class haptik:

	// inherit from basic flext class

	public flext_dsp

{

	// obligatory flext header (class name,base class name)

	FLEXT_HEADER(haptik,flext_dsp)



	public:

		// constructor

		haptik();

		~haptik();



	protected:

		void m_off(); // method to set the device on

		void m_on(); // method to set the device on

		void m_dev(int d); // method to set the device ID

		void m_rate(int r); // method to set the device ID

		void m_callback(HaptikData& data);// device callback



	private:

		FLEXT_CALLBACK(m_on);

		FLEXT_CALLBACK(m_off);

		FLEXT_CALLBACK_I(m_dev);

		FLEXT_CALLBACK_I(m_rate);

};



haptik::haptik()

{

	// define inlets:

	// first inlet must always be of type anything (or signal for dsp objects)

	AddInSignal("dev, on, off, rate, position x or force x"); // signal inlet for
force



	// register methods

	// set up tagged methods for the default inlet (0)

	// the underscore _ after CADDMETHOD indicates that a message tag is used



	FLEXT_ADDMETHOD_(0,"on",m_on); // register method for tag "on"

	FLEXT_ADDMETHOD_(0,"off",m_off); // register method for tag "off"

	FLEXT_ADDMETHOD_I(0,"dev",m_dev); // register method for tag "dev" and int
argument

	FLEXT_ADDMETHOD_I(0,"rate",m_rate); // register method for tag "rate" and int
argument

}



haptik::~haptik()

{

	if (haptikDeviceStatus)

		hapticDevice->Stop();



	// release interface

	RELEASE_HAPTIK_INTERFACE(hapticDevice);

}



void haptik::m_on()

{

	if (!haptikDeviceStatus)

	{



		// warn user if no device has been found

		if (haptikWrapper.numberOfDevices == 0)

		{

			post("%s - No Haptik Devices Found! Checkout configuration
file!",thisName());

			return;

		}

		// list installed devices

		if (haptikID == -1)

		{

			post("%s - Installed devices:",thisName());

			for(UINT32 i = 0 ; i<haptikWrapper.numberOfDevices ; i++)

				post("%s - \t[%d] %s (%s) by
%s",thisName(),i,haptikWrapper.device[i].name,haptikWrapper.device[i].model,haptikWrapper.device[i].manufacturer);

			post("%s - Please choose your device using a message box",thisName());

			return;

		}



		// ask for an interface to that device

		hapticDevice = (IHaptikDeviceInterface) haptikWrapper.GetDeviceInterface(
haptikID == -1 ? HAPTIK_DEFAULT_DEVICE : haptikID );

		if (hapticDevice == NULL)

		{

		post("%s - Invalid Interface. Is device connected?",thisName());

		return;

		}



		// set an object-based callback

		uRes =
hapticDevice->Init(METHOD_ADDRESS(haptik,m_callback),OBJECT_ADDRESS(haptik,*this));

		if FAILED(uRes)

		{

			RELEASE_HAPTIK_INTERFACE(hapticDevice);

			post("%s - Failed to Initialize device",thisName());

			return;

		}



		// set rate

		uRes = hapticDevice->SetRate(haptikRate);

		if FAILED(uRes)

		{

			RELEASE_HAPTIK_INTERFACE(hapticDevice);

			post("%s - Failed to Start device",thisName());

			return;

		}



		// start device

		uRes = hapticDevice->Start();

		if FAILED(uRes)

		{

			RELEASE_HAPTIK_INTERFACE(hapticDevice);

			post("%s - Failed to Start device",thisName());

			return;

		}



		// user interaction...

		post("%s - Device is on",thisName());

		haptikDeviceStatus = true ;

	}

	else

		post("%s - Device is already on!",thisName());

}



void haptik::m_off()

{

	if (haptikDeviceStatus)

	{

		post("%s - Device is off",thisName());

		hapticDevice->Stop();



		// release interface

		RELEASE_HAPTIK_INTERFACE(hapticDevice);



		haptikDeviceStatus = false;

	}

	else

		post("%s - Device is already off!",thisName());

}



void haptik::m_dev(int d)

{

	if ((d<haptikWrapper.numberOfDevices) && (d>-1))

	{

		if (!haptikDeviceStatus)

		{

			haptikID = (UINT32)d;

			post("%s - Device [%d] chosen",thisName(),d);

		}

		else

			post("%s - Please disable the current device first",thisName());

	}

	else

		post("%s - No such device!",thisName());

}



void haptik::m_rate(int r)

{

	if ((r>=1) && (r<=1000))

	{

		if (haptikDeviceStatus)

		{

			uRes = hapticDevice->SetRate((UINT32)r);

			if FAILED(uRes)

			{

				RELEASE_HAPTIK_INTERFACE(hapticDevice);

				post("%s - Failed to set device rate",thisName());

				return;

			}

		}

		haptikRate=(UINT32)r;

		post("%s - Rate set at: %i",thisName(),haptikRate);

	}

	else

		post("%s - Please choose a rate between 1 and 1000 Hz",thisName());

}



void haptik::m_callback(HaptikData& data)

{

	pdata.position = data.position;

	data.forceFeedback = fdata.forceFeedback;

	//data.torqueFeedback = Vector3(0,0,0);

}



//-----------------------------------------------------------------------

class haptikposition:

	// inherit from basic flext class

	public haptik

{

	// obligatory flext header (class name,base class name)

	FLEXT_HEADER(haptikposition,haptik)



	public:

		haptikposition();



	protected:

		virtual void m_signal(int n, float *const *in, float *const *out);

};



FLEXT_LIB("haptik~.position",haptikposition);



haptikposition::haptikposition()

{

	// define outlets:

	AddOutSignal("position (3 element list)"); //signal outlet for position x

	AddOutSignal("position (3 element list)"); //signal outlet for position y

	AddOutSignal("position (3 element list)"); //signal outlet for position z

}



void haptikposition::m_signal(int n, float *const *in, float *const *out)

{

	float *outx = out[0];

	float *outy = out[1];

	float *outz = out[2];



	while (n--)

	{

		if (haptikDeviceStatus)

		{

			// output position

			*outz++ = pdata.position.z;

			*outy++ = pdata.position.y;

			*outx++ = pdata.position.x;

		}

	}

} // end m_signal



//-----------------------------------------------------------------------

class haptikforce:

	// inherit from basic flext class

	public haptik

{

	// obligatory flext header (class name,base class name)

	FLEXT_HEADER(haptikforce,haptik)



	public:

		haptikforce();



	protected:

		virtual void m_signal(int n, float *const *in, float *const *out);

};



FLEXT_LIB("haptik~.force",haptikforce);



haptikforce::haptikforce()

{

	// define inlets:

	// first inlet must always be of type anything (or signal for dsp objects)

	AddInSignal("force (3 element list)"); // signal inlet for force y

	AddInSignal("force (3 element list)"); // signal inlet for force z

}



void haptikforce::m_signal(int n, float *const *in, float *const *out)

{

	const float *insx = in[0];

	const float *insy = in[1];

	const float *insz = in[2];



	while (n--)

	{

		if (haptikDeviceStatus)

		{

			// input force

			fdata.forceFeedback.x = *insx++;

			fdata.forceFeedback.y = *insy++;

			fdata.forceFeedback.z = *insz++;

			fdata.torqueFeedback = Vector3(0,0,0);

		}

	}

} // end m_signal



//-----------------------------------------------------------------------

static void lib_setup()

{

	post("Haptik~ Library v0.01");

	post("Christian Frisson - 06/07/31");

	post("");

	// call the objects' setup routines

	FLEXT_SETUP(haptikposition);

	FLEXT_SETUP(haptikforce);



	haptikDeviceStatus = false;

	haptikID = -1;

	haptikRate = 1000;

}

// setup the library

FLEXT_LIB_SETUP(haptik,lib_setup)




More information about the Pd-list mailing list