Hi,
I'm currently using flext to develop a library of externals itself wrapping another C++ library. On the latter library, some setup classes have to be instanciated once only in a whole application. What's the way to benefit from inheritance in order to:
library in order to create each only once;
As I'm a poor C++ coder, the only ugly way I've yet found to circumvent this is declaring instances of those setup classes outside flext classes, statically. But for sure those variable won't get deleted and Pd sends a "read memory" error message when it's being closed...
Any idea?
Thanks, Christian
Hi Christian, although it would be beneficial to have some example code, i would guess you need the following: Set a static counter to 0 in the beginning, when an object is created, check if the counter is 0 and create your "static" instances - increment the counter in any case. In object destructors, decrement the counter. If it has reached 0, destroy your "static" instances.
greetings, Thomas
Am 31.07.2006 um 01:50 schrieb Christian Frisson:
Hi,
I'm currently using flext to develop a library of externals itself wrapping another C++ library. On the latter library, some setup classes have to be instanciated once only in a whole application. What's the way to benefit from inheritance in order to:
- declare instances of those setup classes only in the base flext
class of the library in order to create each only once;
- share access with externals, being flext inherited classes of the
base class?
As I'm a poor C++ coder, the only ugly way I've yet found to circumvent this is declaring instances of those setup classes outside flext classes, statically. But for sure those variable won't get deleted and Pd sends a "read memory" error message when it's being closed...
Any idea?
Thanks, Christian
PD-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
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)
Hallo, Christian Frisson hat gesagt: // Christian Frisson wrote:
On the list of yet unhandled important issues:
- the "m_signal" functions are not in sync with the frequency rate of the haptic
device;
And you sure won't get them to sync (easily), as Pd's signal rates are synched with the soundcard and not with the haptic device.
Did you consider to not write a signal external at all? Haptic rates are generally much much lower than dsp signals.
So I don't think, a signal external is what you need here, a simple message external would be much better. Flext makes it easier to have a thread running that watches the haptic device for example.
Frank Barknecht _ ______footils.org_ __goto10.org__
Hi Christian,
the basic question is if you really need signals for input/output of
force/position.
Obviously you aren't using the individual samples of a block, hence
it's a waste of cpu. You are proably better off with messages, where
you can also use 3-element lists for input/output of data.
Concerning your "static" variables, they are obviously not initialized
which will result in undefined behaviour. For the "link problems" it's
relevant how and where you move the variables, which is impossible to
anticipate without the actual code.
As far as i can see you cannot really separate the position and force
into two objects as they share the same resource. Having more than one
instance of an object will yield aliased results.
best greetings,
Thomas
Am 01.08.2006 um 07:59 schrieb Christian Frisson:
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
usedFLEXT_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 argumentFLEXT_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].m odel,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 xAddOutSignal("position (3 element list)"); //signal outlet for
position yAddOutSignal("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)