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:
device;
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)